/**
 @file drv_api.c

 @author  Copyright (C) 2011 Centec Networks Inc.  All rights reserved.

 @date 2015-10-09

 @version v1.0

 The file contains all chip APIs of Driver layer
*/
#include "sal.h"
#include "drv_api.h"
#include "usw/include/drv_common.h"
#include "usw/include/drv_error.h"
#include "usw/include/drv_io.h"
#include "usw/include/drv_chip_ctrl.h"
#include "usw/include/drv_app.h"
#include "dal.h"

#define DRV_MEP_LOCK(lchip)   \
    if(p_drv_master[lchip]->p_mep_mutex) {sal_mutex_lock(p_drv_master[lchip]->p_mep_mutex);}
#define DRV_MEP_UNLOCK(lchip) \
    if(p_drv_master[lchip]->p_mep_mutex) {sal_mutex_unlock(p_drv_master[lchip]->p_mep_mutex);}

#define FIB_ACC_LOCK(lchip)    \
  if(p_drv_master[lchip]->fib_acc_mutex) {sal_mutex_lock(p_drv_master[lchip]->fib_acc_mutex);}
#define FIB_ACC_UNLOCK(lchip)  \
  if(p_drv_master[lchip]->fib_acc_mutex) {sal_mutex_unlock(p_drv_master[lchip]->fib_acc_mutex);}

#if (1 == SDK_WORK_PLATFORM)
extern int32 dal_init_sim_io_cb(uint8 lchip);
#endif
/* use for testing cpu endian */
struct endian_test_e
{
    uint32 test1    : 1;
    uint32 test2    : 31;
};
typedef struct endian_test_e endian_test_t;
drv_master_t g_drv_master[DRV_MAX_CHIP_NUM];
drv_master_t* p_drv_master[DRV_MAX_CHIP_NUM] = {NULL};
drv_chip_info_t g_drv_chip[DRV_MAX_CHIP_NUM];

uint8 drv_vchip_pp_base[DRV_MAX_CHIP_NUM] = {0};
uint8 drv_vchip_pp_num[DRV_MAX_CHIP_NUM]  = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
uint8 drv_pcie_cmd_bmp[DRV_MAX_CHIP_NUM]  = {0};
uint8 drv_map_ldev[DRV_MAX_CHIP_NUM]  = {0};

#if (SDK_WORK_PLATFORM == 1)
uint8 g_drv_vchip_mode = 0;
#endif

#ifdef EMULATION_ENV
uint8 g_drv_emu_first_pp_bmp = 0x4;
#endif
#define __DRV_INTERNAL_FUNCTION_

/**
 @brief get host type automatically. Little-Endian or Big-Endian.
*/
STATIC void
_drv_get_host_type(uint8 lchip)
{
    endian_test_t test;
    uint32* p_test = NULL;

    p_test = (uint32 *)&test;
    *p_test = 0;
    test.test1 = 1;

    if (*p_test == 0x01)
    {
        p_drv_master[lchip]->host_type = HOST_LE;
    }
    else
    {
        p_drv_master[lchip]->host_type = HOST_BE;
    }

    return;
}


/*mep table need mask cfg, TBD*/
STATIC int32
_drv_ioctl(uint8 lchip, int32 index, uint32 cmd, uint8 oper_bmp, void* val)
{
    int32 action;
    tbls_id_t tbl_id;
    uint16 field_id;
    uint32* p_data_entry = NULL;
    int32 ret = DRV_E_NONE;
   #ifndef SDK_IN_KERNEL
    uint32  data_entry[MAX_ENTRY_WORD];
   #endif

    action = DRV_IOC_OP(cmd);
    tbl_id = DRV_IOC_MEMID(cmd);
    field_id = DRV_IOC_FIELDID(cmd);

    if (action == DRV_IOC_READ || DRV_ENTRY_FLAG != field_id)
    {
#ifdef SDK_IN_KERNEL
        p_data_entry = (uint32*)mem_malloc(MEM_SYSTEM_MODULE, sizeof(uint32)*MAX_ENTRY_WORD);
        if (!p_data_entry )
        {
            return DRV_E_NO_MEMORY;
        }
#else
        p_data_entry = data_entry;
#endif
    }

    switch (action)
    {
    case DRV_IOC_WRITE:

        /* Write Sram one field of the entry */
        if (DRV_ENTRY_FLAG != field_id)
        {
            DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_READ](lchip, index, cmd, oper_bmp, p_data_entry), ret, out);
            DRV_IF_ERROR_GOTO(drv_set_field(lchip, tbl_id, field_id, p_data_entry, (uint32*)val), ret, out);
            DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_WRITE](lchip, index, cmd, oper_bmp, p_data_entry), ret, out);
        }
        else
        {
            DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_WRITE](lchip, index, cmd, oper_bmp, (uint32*)val), ret, out);
        }

        break;
    case DRV_IOC_READ:
        /* Read Sram one field of the entry */
        DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_READ](lchip, index, cmd, oper_bmp, p_data_entry), ret, out);
        if (DRV_ENTRY_FLAG != field_id)
        {
            DRV_IF_ERROR_GOTO(drv_get_field(lchip, tbl_id, field_id, p_data_entry, (uint32*)val), ret, out);
        }
        else
        {
            sal_memcpy((uint32*)val, p_data_entry, TABLE_ENTRY_SIZE(lchip, tbl_id));
        }

        break;

    default:
        break;
    }

out:

 #ifdef SDK_IN_KERNEL
    if (p_data_entry)
    {
        mem_free(p_data_entry);
    }
#endif

    return ret;
}

/*used for TMM oam mask write*/
STATIC int32
_drv_oam_mask_ioctl(uint8 lchip, int32 index, uint32 cmd, uint8 oper_bmp, void* val)
{
    uint32* value = NULL;
    uint32* mask = NULL;
#if(SDK_WORK_PLATFORM == 1)
    tbls_id_t tbl_id;
    uint32 value_tmp[32] = {0};
    uint32 value_wr[32] = {0};
    uint32 i=0;
    uint32 tbl_size =0;
#endif
    mask = (uint32 *)(((tbl_entry_t*)val)->mask_entry);
    value = (uint32 *)(((tbl_entry_t*)val)->data_entry);

#if(SDK_WORK_PLATFORM == 0)
    /*write mask*/
    DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_WRITE](lchip, 0, DRV_IOW(DsMpMask_t, DRV_ENTRY_FLAG), oper_bmp, mask));

    /*write data*/
    DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_WRITE](lchip, index, cmd, oper_bmp, value));
#else
    tbl_id = DRV_IOC_MEMID(cmd);
#if 0 
    if (oper_bmp>>6 == 0x3)
    {
        oper_bmp = 0x40;
    }
    #endif
    DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_READ](lchip, index, cmd, oper_bmp, value_tmp));
    tbl_size = TABLE_ENTRY_SIZE(lchip, tbl_id);
    tbl_size = (tbl_size % 4)? (tbl_size / 4 + 1) : (tbl_size / 4);
    for (i = 0; i < tbl_size; i++)
    {
        value_wr[i]=( value_tmp[i] & mask[i]) | (value[i]&(~mask[i]));
    }

    DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_WRITE](lchip, index, cmd, oper_bmp, value_wr));
#endif

    return DRV_E_NONE;
}

/*used for D2/TM oam mask write*/
STATIC int32
_drv_tm_oam_mask_ioctl(uint8 lchip, int32 index, uint32 cmd, uint8 oper_bmp, void* val)
{
    uint32* value = NULL;
    uint32* mask = NULL;
#if(SDK_WORK_PLATFORM == 1)
    tbls_id_t tbl_id;
    uint32 value_wr[32] = {0};
    uint32 tbl_size =0;
#else
    uint8 match = 0;
#endif
    uint32 value_tmp[32] = {0};
    uint32 cmd_oam = 0;
    uint8 i = 0;

    mask = (uint32 *)(((tbl_entry_t*)val)->mask_entry);
    value = (uint32 *)(((tbl_entry_t*)val)->data_entry);

#if(SDK_WORK_PLATFORM == 0)
    cmd_oam = DRV_IOR(DRV_IOC_MEMID(cmd), DRV_IOC_FIELDID(cmd));
    do
    {
        match = 1;
        /*write mask*/
        DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_WRITE](lchip, 0, DRV_IOW(OamDsMpDataMask_t, DRV_ENTRY_FLAG), oper_bmp, mask));

        /*write data*/
        DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_WRITE](lchip, index, cmd, oper_bmp, value));
        /*read data*/
        _drv_ioctl(lchip, index, cmd_oam, oper_bmp, value_tmp);
        for (i = 0; i < (sizeof(DsBfdRmep_m) >> 2); i++)
        {
            if ((value[i] & (~mask[i])) != (value_tmp[i] & (~mask[i])))
            {
                match = 0;
                break;
            }
        }
    }
    while(!match);
#else
    /*write data with mask for uml*/
    tbl_id = DRV_IOC_MEMID(cmd);
    cmd_oam = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
    DRV_IF_ERROR_RETURN(_drv_ioctl(lchip, index, cmd_oam, oper_bmp, value_tmp));

    tbl_size = TABLE_ENTRY_SIZE(lchip, tbl_id);
    tbl_size = (tbl_size % 4)? (tbl_size / 4 + 1) : (tbl_size / 4);
    for (i = 0; i < tbl_size; i++)
    {
        value_wr[i]=( value_tmp[i] & mask[i]) | (value[i]&(~mask[i]));
    }
    DRV_IF_ERROR_RETURN(_drv_ioctl(lchip, index, cmd, oper_bmp, value_wr));
#endif

    return DRV_E_NONE;
}

#if(SDK_WORK_PLATFORM == 0)
STATIC int32
drv_ioctl_aps_mask_api(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32 * val)
{
    uint32 cmd_aps = 0;
    DsApsBridge_m data_mask;
    DsApsBridgeMask_m aps_mask;
    uint32 field_id = 0;
    uint32 tbl_id = 0;
    uint32 field_val = 0;
    uint32 action;

    action = DRV_IOC_OP(cmd);
    if (DRV_IOC_READ == action)
    {
        return DRV_E_NONE;
    }

    field_id = DRV_IOC_FIELDID(cmd);

    if (DRV_ENTRY_FLAG == field_id)
    {
        /*per entry write, mask should be all 0*/
        sal_memset(&data_mask, 0, sizeof(DsApsBridge_m));
    }
    else
    {
        sal_memset(&data_mask, 0xff, sizeof(DsApsBridge_m));
        DRV_IOW_FIELD(lchip, DsApsBridge_t, field_id, &field_val, &data_mask);
    }

    field_val = 1;
    if (p_drv_master[lchip]->dev_type == DRV_DUET2)
    {
        /*write mask*/
        cmd_aps = DRV_IOW(DsApsBridgeMask_t, DRV_ENTRY_FLAG);
        DRV_IF_ERROR_RETURN(_drv_ioctl(lchip, 0, cmd_aps, oper_bmp, &data_mask));
    }
    else
    {
        sal_memset(&aps_mask, 0, sizeof(DsApsBridgeMask_m));
        /*write mask*/
        if ((p_drv_master[lchip]->dev_type == DRV_TSINGMA))
        {
            drv_set_field(lchip, MetFifoDsApsMask_t, MetFifoDsApsMask_dsApsMemMask_f, &aps_mask, (uint32 *)&data_mask);
            drv_set_field32(lchip, MetFifoDsApsMask_t, MetFifoDsApsMask_dsApsMemMaskEn_f, (uint32 *)&aps_mask, field_val);
            tbl_id = MetFifoDsApsMask_t;
        }
        else if ((p_drv_master[lchip]->dev_type == DRV_TSINGMA_MX) || (p_drv_master[lchip]->dev_type == DRV_TSINGMA_GX))
        {
            drv_set_field(lchip, MetFifoShareDsApsMask_t, MetFifoShareDsApsMask_dsApsMemMask_f, &aps_mask, (uint32 *)&data_mask);
            drv_set_field32(lchip, MetFifoShareDsApsMask_t, MetFifoShareDsApsMask_dsApsMemMaskEn_f, (uint32 *)&aps_mask, field_val);
            tbl_id = MetFifoShareDsApsMask_t;
        }
        cmd_aps = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DRV_IF_ERROR_RETURN(_drv_ioctl(lchip, 0, cmd_aps, oper_bmp, &aps_mask));
    }

    return DRV_E_NONE;
}

/* Only TM table using drain dis:
    DsFibHost0FcoeHashKey_t
    DsFibHost0Ipv4HashKey_t
    DsFibHost0Ipv6McastHashKey_t
    DsFibHost0Ipv6UcastHashKey_t
    DsFibHost0MacIpv6McastHashKey_t
    DsFibHost0TrillHashKey_t
*/
STATIC int32
drv_ioctl_drain_dis_api(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)
{
    FibAccDrainEnable_m fib_drain_en;
    int32 ret = DRV_E_NONE;
    uint32 cmd_tmp = 0;
    uint8 action = 0;

    action = DRV_IOC_OP(cmd);

    SetFibAccDrainEnable(V, agingReqDrainEnable_f, &fib_drain_en, 0);
    SetFibAccDrainEnable(V, learnReqDrainEnable_f, &fib_drain_en, 0);

    FIB_ACC_LOCK(lchip);
    cmd_tmp = DRV_IOW(FibAccDrainEnable_t, DRV_ENTRY_FLAG);
    _drv_ioctl(lchip, 0, cmd_tmp, oper_bmp, &fib_drain_en);

    if (DRV_IS_DUET2(lchip))
    {
        /*Notice:Duet2 dsmac table need process here */
        ret = _drv_ioctl(lchip, index, cmd, oper_bmp, val);
    }
    else
    {
        ret = p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][action](lchip,index, cmd, oper_bmp, val);
    }

    SetFibAccDrainEnable(V, agingReqDrainEnable_f, &fib_drain_en, 1);
    SetFibAccDrainEnable(V, learnReqDrainEnable_f, &fib_drain_en, 1);
    _drv_ioctl(lchip, 0, cmd_tmp, oper_bmp, &fib_drain_en);
    FIB_ACC_UNLOCK(lchip);
    return ret;
}
#endif
#define __DRV_API__
int32
drv_tcam_write_lock(uint8 lchip)
{
    DRV_INIT_CHECK(lchip);
    sal_mutex_lock(p_drv_master[lchip]->p_tcam_write_mutex);

    return DRV_E_NONE;
}

int32
drv_tcam_write_unlock(uint8 lchip)
{
    DRV_INIT_CHECK(lchip);
    sal_mutex_unlock(p_drv_master[lchip]->p_tcam_write_mutex);

    return DRV_E_NONE;
}

uint32
drv_get_const_value(uint8 lchip, drv_constant_t type)
{
#if 0
    if (lchip >= DRV_MAX_CHIP_NUM || !p_drv_master[lchip] || !p_drv_master[lchip]->init_done)
    {
        return 0;
    }

    if(type >= DRV_CONSTANT_MAX)
    {
        return 0;
    }
#endif
    return p_drv_master[lchip]->p_enum_value[type];
}

int32
drv_get_enum_type(uint8 lchip, uint32 start, uint32 end, uint32 value)
{
    uint32 type = 0;

    for (type = start; type <= end; type++)
    {
        if (value == DRV_CONST(type))
        {
            return type;
        }
    }

    return DRV_DMA_MAX_CHAN_ID;
}

/**
  @driver set gchip id for lchip
*/
int32
drv_set_gchip_id(uint8 lchip, uint8 gchip_id)
{
    DRV_INIT_CHECK(lchip);
    p_drv_master[lchip]->g_lchip = gchip_id;
    return DRV_E_NONE;
}

/**
  @driver get gchip id for lchip
*/
int32
drv_get_gchip_id(uint8 lchip, uint8* gchip_id)
{
    DRV_INIT_CHECK(lchip);
    *gchip_id = p_drv_master[lchip]->g_lchip;
    return DRV_E_NONE;
}

/**
  @driver get environmnet type interface
*/
int32
drv_get_platform_type(uint8 lchip, drv_work_platform_type_t *plaform_type)
{
    DRV_INIT_CHECK(lchip);

    if (p_drv_master[lchip])
    {
       *plaform_type = p_drv_master[lchip]->plaform_type;
        return DRV_E_NONE;
    }
    else
    {
        DRV_DBG_INFO("@@@ERROR, Driver is not initialized!\n");
        return  DRV_E_NOT_INIT;
    }
}

/**
  @driver get host type interface
*/
int32
drv_get_host_type (uint8 lchip)
{
    DRV_INIT_CHECK(lchip);

    return p_drv_master[lchip]->host_type;
}
int32 drv_get_field_name_by_bit(uint8 lchip, tbls_id_t tbl_id, uint32 bit_offset, char* field_name)
{
    uint16 loop = 0;
    uint16 loop1 = 0;
    fields_t* p_field = NULL;
    segs_t* p_seg = NULL;
    uint8 words = bit_offset / 32;
    uint8 bits = bit_offset%32;

    DRV_INIT_CHECK(lchip);
    p_field = TABLE_FIELD_INFO_PTR(lchip, tbl_id);
    for(loop=0; loop < TABLE_FIELD_NUM(lchip, tbl_id); loop++)
    {
        p_field = TABLE_FIELD_INFO_PTR(lchip, tbl_id)+loop;
        p_seg = p_field->ptr_seg;
        for(loop1 = 0; loop1 < p_field->seg_num; loop1++)
        {
            p_seg += loop1;
            if((p_seg->word_offset == words) && (bits >= p_seg->start) && (bits < (p_seg->start+p_seg->bits)))
            {
                sal_strcpy(field_name, FIELD_NAME(lchip, tbl_id, loop));
                return DRV_E_NONE;
            }
        }
    }

    return DRV_E_NOT_FOUND;
}
/**
  @driver get table property
*/
int32
drv_get_table_property(uint8 lchip, uint8 type, tbls_id_t tbl_id, uint32 index, void* value)
{
    int32 ret = 0;

    if (!value)
    {
        return DRV_E_INVALID_ADDR;
    }

    DRV_TBL_ID_VALID_CHECK(lchip, tbl_id);
    DRV_INIT_CHECK(lchip);

    switch(type)
    {
        case DRV_TABLE_PROP_TYPE:
            *((uintptr*)value) = drv_usw_get_table_type(lchip, tbl_id);

            break;
        case DRV_TABLE_PROP_HW_ADDR:
        {
            uint32 value_32 = 0;
            ret = drv_usw_table_get_hw_addr(lchip, tbl_id, index, &value_32, 0);
            *((uint32*)value) = value_32;
        }
            break;

        case DRV_TABLE_PROP_GET_NAME:
            ret = drv_usw_get_tbl_string_by_id(lchip, tbl_id, (char*)value);
            break;

        case DRV_TABLE_PROP_BITMAP:
            *((uint32*)value) = DYNAMIC_BITMAP(lchip, tbl_id)[0];
            break;

        case DRV_TABLE_PROP_FIELD_NUM:
            *((uint32*)value) = TABLE_FIELD_NUM(lchip, tbl_id);
            break;
        case DRV_TABLE_PROP_TCAM_KEY_SIZE:
            *((uintptr*)value) = TCAM_EXT_INFO_PTR(lchip, tbl_id)->key_size;
            break;
        case DRV_TABLE_PROP_TCAM_START_SIZE:/*index used as block id*/
            *((uintptr*)value) = TCAM_EXT_INFO_PTR(lchip, tbl_id)->tcam_alloc_info.tcam_mem_entry_start_index[index];
            break;
        case DRV_TABLE_PROP_TABLE_MAX_IDX:
            *((uintptr*)value) = TABLE_INFO(lchip, tbl_id).entry?(TABLE_INFO(lchip, tbl_id).entry):(TABLE_EXT_INFO(lchip, tbl_id).entry);
            break;
        case DRV_TABLE_PROP_TABLE_ENTRY_SIZE:
            *((uintptr*)value) = TABLE_INFO(lchip, tbl_id).byte;
            break;
        case DRV_TABLE_PROP_TABLE_DATA_BASE:
            *((uintptr*)value) = TABLE_INFO(lchip, tbl_id).entry?(TABLE_INFO(lchip, tbl_id).addrs[index]):(TABLE_EXT_INFO(lchip, tbl_id).addrs[index]);
            break;
        case DRV_TABLE_PROP_TABLE_NAME:
            *(uintptr*)value = (uintptr)p_drv_master[lchip]->p_tbl_name[p_drv_master[lchip]->p_tbl_mapping[tbl_id]].ptr_tbl_name;
            break;
        case DRV_TABLE_PROP_SDB_INFO:
            drv_sdb_get_table_enable(lchip, tbl_id, value);
            break;
        case DRV_TABLE_PROP_FIELD_INFO:
            *(uintptr*)value = (uintptr)&TABLE_FIELD_INFO_PTR(lchip, tbl_id)[index];
            break;
        default:
            ret = DRV_E_INVALID_TBL;
            break;
    }

    return ret;
}

/**
@brief Get a field  valued of a memory data entry
*/
void*
drv_get_table_property_value(uint8 lchip, uint8 type, tbls_id_t tbl_id, uint32 index)
{
    void* value = NULL;
    drv_get_table_property(lchip, type, tbl_id, index, &value);
    return value;
}

/**
  @driver set chip access type
*/
int32
drv_set_access_type(uint8 lchip, drv_access_type_t access_type)
{
    drv_work_platform_type_t platform_type;
    DRV_INIT_CHECK(lchip);

    drv_get_platform_type(lchip, &platform_type);
    if ((platform_type != HW_PLATFORM) && (access_type != DRV_PCI_ACCESS))
    {
        return DRV_E_INVAILD_TYPE;
    }

     if (access_type == DRV_PCI_ACCESS)
    {
        p_drv_master[lchip]->drv_chip_read_ext = g_dal_op.pci_read_ext2;/*with mask*/
        p_drv_master[lchip]->drv_chip_write_ext = g_dal_op.pci_write_ext2;  /*with mask*/
        p_drv_master[lchip]->drv_chip_read = g_dal_op.pci_read_ext;
        p_drv_master[lchip]->drv_chip_write = g_dal_op.pci_write_ext;
#if (defined(TSINGMA_MX) || defined(TSINGMA_GX)  || defined(ARCTIC))&& (1 == SDK_WORK_PLATFORM)
        p_drv_master[lchip]->burst_en = 0;
#else
        p_drv_master[lchip]->burst_en = 1;
#endif

    }
    else if (access_type == DRV_I2C_ACCESS)
    {
        p_drv_master[lchip]->drv_chip_read = drv_usw_i2c_read_chip;
        p_drv_master[lchip]->drv_chip_write = drv_usw_i2c_write_chip;
        p_drv_master[lchip]->drv_chip_read_ext = drv_usw_i2c_read_chip_ext;
        p_drv_master[lchip]->drv_chip_write_ext = drv_usw_i2c_write_chip;
        p_drv_master[lchip]->burst_en = 0;

    }

    p_drv_master[lchip]->access_type = access_type;

    return DRV_E_NONE;
}

/**
  @driver get chip access type
*/
int32
drv_get_access_type(uint8 lchip, drv_access_type_t* p_access_type)
{
    DRV_INIT_CHECK(lchip);
    *p_access_type = p_drv_master[lchip]->access_type;

    return DRV_E_NONE;
}
/**
  @driver install drv io/app interface
*/
int32
drv_install_api(uint8 lchip, drv_io_callback_fun_t* cb)
{
    if (lchip >= DRV_MAX_CHIP_NUM)
    {
        return DRV_E_NOT_INIT;
    }

    if (NULL == cb)
    {
        return DRV_E_NOT_INIT;
    }

#if defined (TSINGMA_MX) || defined (TSINGMA_GX) || defined (ARCTIC)
        p_drv_master[lchip]->drv_io_api.drv_sram_tbl_read = cb->drv_sram_tbl_read;
        p_drv_master[lchip]->drv_io_api.drv_sram_tbl_write = cb->drv_sram_tbl_write;
        p_drv_master[lchip]->drv_io_api.drv_tcam_tbl_read = cb->drv_tcam_tbl_read;
        p_drv_master[lchip]->drv_io_api.drv_tcam_tbl_write = cb->drv_tcam_tbl_write;
        p_drv_master[lchip]->drv_io_api.drv_tcam_tbl_remove = cb->drv_tcam_tbl_remove;
#else
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_READ] = cb->drv_sram_tbl_read;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_WRITE] = cb->drv_sram_tbl_write;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;

        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_READ] = cb->drv_sram_tbl_read;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_WRITE] = cb->drv_sram_tbl_write;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;

        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_TCAM][DRV_IOC_READ] = cb->drv_tcam_tbl_read;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_TCAM][DRV_IOC_WRITE] = cb->drv_tcam_tbl_write;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_TCAM][DRV_IOC_REMOVE] = cb->drv_tcam_tbl_remove;
#endif



    return DRV_E_NONE;
}


int32  drv_field_support_check(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id)
{
    fields_t* field = NULL;
    DRV_TBL_ID_VALID_CHECK(lchip, tbl_id);

    field = TABLE_FIELD_INFO_PTR(lchip, tbl_id) + field_id;
    if (tbl_id != TABLE_INFO(lchip, tbl_id).tbl_id || 0 == field->bits || field_id >= TABLE_FIELD_NUM(lchip, tbl_id))
    {
        return DRV_E_INVALID_FLD;
    }

    return DRV_E_NONE;
}

/* this func get total used bits cnt in a table */
uint32
drv_get_table_max_band(uint8 lchip, uint32 tbl_id)
{
    uint8 key_word_num = 0;
    uint16 field_id = 0;
    uint16 field_max_band = 0;
    uint16 temp_max_band = 0;
    uint16 xkey_max_band = 0;
    if (!TABLE_EXT_INFO_PTR(lchip, tbl_id) || !TABLE_EXT_INFO_CONTENT_PTR(lchip, tbl_id))
    {
        return 0xFFFF;
    }
    if (3 == TABLE_EXT_TYPE(lchip, tbl_id))
    {
        key_word_num = TABLE_ENTRY_SIZE(lchip, tbl_id)>>3;
        xkey_max_band = (TABLE_FIELD_INFO_PTR(lchip, DsEgressScl0XHashKey_t)[DsEgressScl0XHashKey_u1_gXKey_data_f].ptr_seg[0].word_offset << 5)
                        + TABLE_FIELD_INFO_PTR(lchip, DsEgressScl0XHashKey_t)[DsEgressScl0XHashKey_u1_gXKey_data_f].ptr_seg[0].start
                        + TABLE_FIELD_INFO_PTR(lchip, DsEgressScl0XHashKey_t)[DsEgressScl0XHashKey_u1_gXKey_data_f].ptr_seg[0].bits;
    }
    else
    {
        key_word_num = TABLE_ENTRY_SIZE(lchip, tbl_id)>>2;
        xkey_max_band = key_word_num << 5;
    }

    for (field_id=0; field_id<TABLE_FIELD_NUM(lchip, tbl_id); field_id++)
    {
        if (0 == TABLE_FIELD_INFO_PTR(lchip, tbl_id)[field_id].bits)
        {
            continue;
        }
        temp_max_band = (TABLE_FIELD_INFO_PTR(lchip, tbl_id)[field_id].ptr_seg[0].word_offset << 5) + TABLE_FIELD_INFO_PTR(lchip, tbl_id)[field_id].ptr_seg[0].start + TABLE_FIELD_INFO_PTR(lchip, tbl_id)[field_id].ptr_seg[0].bits;
        if (temp_max_band < xkey_max_band && field_max_band < temp_max_band)
        {
            field_max_band = temp_max_band;
        }
    }

    return field_max_band;
}

uint16
drv_get_key_width(uint8 lchip, uint32 tbl_id)
{
    char* field_name = NULL;
    uint16 field_id = 0;
    uint16 field_width = 0;
    #define DRV_FILED_NAME_MATCH(needle)    (\
        sal_strlen(field_name) >= sal_strlen(needle)\
        && !sal_strncmp(field_name, needle, sal_strlen(needle))\
    )
    for (field_id=0; field_id<TABLE_FIELD_NUM(lchip, tbl_id); field_id++)
    {
        field_name = p_drv_master[lchip]->p_tbl_name[p_drv_master[lchip]->p_tbl_mapping[tbl_id]].fields_name[field_id].ptr_field_name;
        if (0 == TABLE_FIELD_INFO_PTR(lchip, tbl_id)[field_id].bits
            || DRV_FILED_NAME_MATCH("xKeyValid")
            || DRV_FILED_NAME_MATCH("valid")
            || DRV_FILED_NAME_MATCH("dsAdIndex")
            || DRV_FILED_NAME_MATCH("hashType")
            || DRV_FILED_NAME_MATCH("hashKeyType")
            || DRV_FILED_NAME_MATCH("sclKeyType")
            || DRV_FILED_NAME_MATCH("flowFieldSel")
            || DRV_FILED_NAME_MATCH("isNshEditDs"))
        {
            continue;
        }
        field_width += TABLE_FIELD_INFO_PTR(lchip, tbl_id)[field_id].bits;
    }
    return field_width;
}

/**
 @brief Get a x field of a memory data entry
 Get memory is always little endian
 Transfer read data from little endian to bigger endian
 when CPU is BE, and used to caculate value using shift with 32 bits data
*/
int32
drv_get_x_field(uint8 lchip, uint8 i_word, uint8 i_start, uint8 i_bits, void* ds, uint32* value)
{
    segs_t segTemp;
    segs_t* seg = NULL;
    uint16 uint32_idx  = 0;
    uint16 word_idx = 0;
    uint16 remain_len  = 0;
    uint16 cross_word  = 0;
    uint32 remain_value = 0;
    uint32 seg_value = 0;
    uint32 remain_bits = 0;
    uint32 word_num = 0;
    uint32 bits = 0;
    uint32* entry  = NULL;

    DRV_INIT_CHECK(lchip);

    DRV_PTR_VALID_CHECK(ds)
    DRV_PTR_VALID_CHECK(value)

    entry = ds;

    segTemp.word_offset = i_word;
    segTemp.start = i_start;
    segTemp.bits = i_bits;
    seg = &segTemp;

    remain_bits = seg->bits;
    word_num = ((seg->start+seg->bits)>>5) + ((seg->start+seg->bits)&0x1F?1:0);

    for (word_idx = 0; word_idx < word_num; word_idx++)
    {
        bits = (remain_bits+(word_idx?0:seg->start)) > 32 ? (32-(word_idx?0:seg->start)) : remain_bits;
        remain_bits -= bits;

        seg_value = (entry[seg->word_offset+word_idx] >> (word_idx?0:seg->start)) & SHIFT_LEFT_MINUS_ONE(bits);

        value[uint32_idx] = (seg_value << remain_len) | remain_value;
        if ((bits + remain_len) == 32)
        {
            remain_value = 0;
            cross_word = 0;
            uint32_idx ++;
        }
        else if ((bits + remain_len) > 32)
        {
            /*create new remain_value */
            remain_value = seg_value >> (32 - remain_len);
            cross_word = 1;
            uint32_idx ++;
        }
        else
        {
            /*create new remain_value */
            remain_value = (seg_value << remain_len) | remain_value;
            cross_word = 0;
        }
        /*create new remain_len */
        remain_len   = (bits + remain_len) & 0x1F; /*rule out bits that exceeds 32*/
    }

    if(cross_word) /* last seg cross word */
    {
        value[uint32_idx] = remain_value;
    }

    return DRV_E_NONE;
}

/**
 @brief register a Memory field to the register field directory
*/
fields_t *
_drv_find_field(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id)
{
    fields_t *p_fld = NULL;
    uint32 i = 0;

    if (!(CHK_TABLE_ID_VALID(lchip, tbl_id)) || !TABLE_FIELD_NUM(lchip, tbl_id))
    {
        DRV_DBG_INFO("ERROR! INVALID TblID or fieldID! TblID: %d, fieldID: %d\n", tbl_id, field_id);
        if (TABLE_NAME(lchip, tbl_id))
        {
            DRV_DBG_INFO("ERROR! INVALID TblName:%s\n", TABLE_NAME(lchip, tbl_id));
        }
        return NULL;
    }

    for (i = 0; i < TABLE_FIELD_NUM(lchip, tbl_id); i++)
    {
         p_fld = TABLE_FIELD_INFO_PTR(lchip, tbl_id) + i;

         if (p_fld && p_fld->field_id == field_id)
         {
             return p_fld;
         }
    }

    return NULL;
}

/**
 @brief Set a x field of a memory data entry
  Set memory is always little endian,
  here use byte order same as Spec Web define,
*/
int32
drv_set_x_field(uint8 lchip, uint8 i_word, uint8 i_start, uint8 i_bits, void* ds, uint32 *value)
{
    //fields_t* field = NULL;
    segs_t* seg = NULL;
    segs_t segTemp;
    uint8  cut_len =  0;
    uint16 array_idx = 0;
    uint16 word_idx = 0;
    uint32 seg_value = 0;
    uint32 value_a = 0;
    uint32 value_b = 0;
    uint32 remain_bits = 0;
    uint32 word_num = 0;
    uint32 bits = 0;
    uint32* entry  = NULL;

    DRV_INIT_CHECK(lchip);
    DRV_PTR_VALID_CHECK(ds)

    entry = ds;

    cut_len = 0;
    array_idx = 0;

    segTemp.word_offset = i_word;
    segTemp.start = i_start;
    segTemp.bits = i_bits;
    seg = &segTemp;

    remain_bits = seg->bits;
    word_num = ((seg->start+seg->bits)>>5) + ((seg->start+seg->bits)&0x1F?1:0);

    for (word_idx = 0; word_idx < word_num; word_idx++)
    {
        bits = (remain_bits+(word_idx?0:seg->start)) > 32 ? (32-(word_idx?0:seg->start)) : remain_bits;
        remain_bits -= bits;

        if ((cut_len + bits) >= 32)
        {
            value_b = (value[array_idx + 1 ] & SHIFT_LEFT_MINUS_ONE((cut_len + bits - 32)));
            value_a = (value[array_idx] >> cut_len) & SHIFT_LEFT_MINUS_ONE((32- cut_len));
            seg_value = (value_b << ((32 - cut_len)& 0x1F)) | value_a;

            array_idx++;
        }
        else
        {
            value_a = (value[array_idx] >> cut_len) & SHIFT_LEFT_MINUS_ONE(bits);
            seg_value =  value_a;
        }

        entry[seg->word_offset+word_idx] &= ~ (SHIFT_LEFT_MINUS_ONE(bits)  << (word_idx?0:seg->start));
        entry[seg->word_offset+word_idx] |= (seg_value << (word_idx?0:seg->start));

        cut_len = (cut_len + bits) & 0x1F; /*rule out bits that exceeds 32*/
    }

    return DRV_E_NONE;
}


/**
 @brief Get a field of a memory data entry
*/
int32
drv_get_field(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id,
                void* ds, uint32* value)
{
    fields_t* field = NULL;
    int32 seg_id;
    segs_t* seg = NULL;
    uint8 uint32_idx  = 0;
    uint16 remain_len  = 0;
    uint16 cross_word  = 0;
    uint32 remain_value = 0;
    uint32 seg_value = 0;
    uint32* entry  = NULL;

    DRV_INIT_CHECK(lchip);

    DRV_PTR_VALID_CHECK(ds)
    DRV_PTR_VALID_CHECK(value)
    DRV_TBL_ID_VALID_CHECK(lchip, tbl_id);

    if (!TABLE_FIELD_NUM(lchip, tbl_id))
    {
        return DRV_E_NONE;
    }

    entry = ds;
    field = TABLE_FIELD_INFO_PTR(lchip, tbl_id) + field_id;
    if (tbl_id != TABLE_INFO(lchip, tbl_id).tbl_id || field_id >= TABLE_FIELD_NUM(lchip, tbl_id) || 0 == field->bits )
    {
         /*DRV_DBG_INFO("ERROR! (drv_get_field): %s(%d), field-%d is not supported\n", TABLE_NAME(lchip, tbl_id), tbl_id, field_id);*/
        *value = 0;
        return 0;
    }

    seg_id = (field->seg_num-1);

    do
    {
        seg = &(field->ptr_seg[seg_id]);
        seg_value = (entry[seg->word_offset] >> seg->start) & SHIFT_LEFT_MINUS_ONE(seg->bits);

        value[uint32_idx] = (seg_value << remain_len) | remain_value;
        if ((seg->bits + remain_len) == 32)
        {
            remain_value = 0;
            cross_word = 0;
            uint32_idx ++;
        }
        else if ((seg->bits + remain_len) > 32)
        {
            /*create new remain_value */
            remain_value = seg_value >> ((32 - remain_len)&0x1F);
            cross_word = 1;
            uint32_idx ++;
        }
        else
        {
            /*create new remain_value */
            remain_value = (seg_value << remain_len) | remain_value;
            cross_word = 0;
        }
        /*create new remain_len */
        remain_len   = (seg->bits + remain_len) & 0x1F; /*rule out bits that exceeds 32*/
        seg_id --;
    }
    while(seg_id>=0);

    if(cross_word) /* last seg cross word */
    {
        value[uint32_idx] = remain_value;
    }

    return DRV_E_NONE;
}

/**
 @brief Set a field of a memory data entry
*/
int32
drv_set_field(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id,
                        void* ds, uint32 *value)
{
    fields_t* field = NULL;
    segs_t* seg = NULL;
    int32 seg_id = 0;
    uint8 cut_len =  0;
    uint8 array_idx = 0;
    uint32 seg_value = 0;
    uint32 value_a = 0;
    uint32 value_b = 0;
    uint32* entry  = NULL;

    DRV_INIT_CHECK(lchip);

    DRV_PTR_VALID_CHECK(ds)
    DRV_TBL_ID_VALID_CHECK(lchip, tbl_id);

    entry = ds;
    /* register field support check */
    field = TABLE_FIELD_INFO_PTR(lchip, tbl_id) + field_id;
    if (tbl_id != TABLE_INFO(lchip, tbl_id).tbl_id || field_id >= TABLE_FIELD_NUM(lchip, tbl_id) || 0 == field->bits )
    {
         /*DRV_DBG_INFO("ERROR! (drv_set_field): tbl_id-%d, name-%s(%d), field-%d is not supported\n", tbl_id, TABLE_NAME(lchip, tbl_id),tbl_id, field_id);*/
        return DRV_E_NONE;
    }


    seg_id = (field->seg_num-1);
    cut_len = 0;

    array_idx = 0;
    do
    {
        seg = &(field->ptr_seg[seg_id]);

        if ((cut_len + seg->bits) >= 32)
        {
            value_b = (cut_len + seg->bits) == 32? 0 : (value[array_idx + 1 ] & SHIFT_LEFT_MINUS_ONE((cut_len + seg->bits - 32)));
            value_a = (value[array_idx] >> cut_len) & SHIFT_LEFT_MINUS_ONE((32- cut_len));
            seg_value = (value_b << ((32 - cut_len)& 0x1F)) | value_a;

            array_idx++;
        }
        else
        {
            value_a = (value[array_idx] >> cut_len) & SHIFT_LEFT_MINUS_ONE(seg->bits);
            seg_value =  value_a;
        }

        entry[seg->word_offset] &= ~ (SHIFT_LEFT_MINUS_ONE(seg->bits)  << seg->start);
        entry[seg->word_offset] |= (seg_value << seg->start);

        cut_len = (cut_len + seg->bits) & 0x1F; /*rule out bits that exceeds 32*/

        seg_id--;
    }
    while(seg_id>=0);

    return DRV_E_NONE;
}

int32
drv_set_field32(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id, uint32* entry, uint32 value)
{
    fields_t* field = NULL;
    segs_t* seg = NULL;

    field = TABLE_FIELD_INFO_PTR(lchip, tbl_id) + field_id;

    if (tbl_id != TABLE_INFO(lchip, tbl_id).tbl_id || field_id >= TABLE_FIELD_NUM(lchip, tbl_id) || 0 == field->bits)
    {
        return DRV_E_NONE;
    }

    if (field->seg_num == 1)
    {
        seg = &(field->ptr_seg[0]);
        entry[seg->word_offset] &= ~(SHIFT_LEFT_MINUS_ONE(seg->bits)  << seg->start);
        entry[seg->word_offset] |= ((value & SHIFT_LEFT_MINUS_ONE(seg->bits)) << seg->start);
    }
    else if(field->seg_num == 2)
    {
        segs_t* seg1 = NULL;

        seg = &(field->ptr_seg[1]);
        entry[seg->word_offset] &= ~(SHIFT_LEFT_MINUS_ONE(seg->bits)  << seg->start);
        entry[seg->word_offset] |= ((value & SHIFT_LEFT_MINUS_ONE(seg->bits)) << seg->start);
        seg1 = &(field->ptr_seg[0]);
        entry[seg1->word_offset] &= ~(SHIFT_LEFT_MINUS_ONE(seg1->bits)  << (seg1->start&0x1F));
        entry[seg1->word_offset] |= (((value>>(seg->bits&0x1F))& SHIFT_LEFT_MINUS_ONE(seg1->bits)) << seg1->start);
    }
    else
    {
        drv_set_field(lchip, tbl_id, field_id, entry, &value);
    }


    return DRV_E_NONE;
}

uint32
drv_get_field32(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id, void* entry)
{
    fields_t* field = NULL;
    segs_t* seg = NULL;
    uint32 value = 0;

    field = TABLE_FIELD_INFO_PTR(lchip, tbl_id) + field_id;

    if (tbl_id != TABLE_INFO(lchip, tbl_id).tbl_id || field_id >= TABLE_FIELD_NUM(lchip, tbl_id) || 0 == field->bits)
    {
        return DRV_E_NONE;
    }

    if (field->seg_num == 1)
    {
        seg = &(field->ptr_seg[0]);
        value = (((uint32*)entry)[seg->word_offset]>>seg->start) & SHIFT_LEFT_MINUS_ONE(seg->bits);
    }
    else if(field->seg_num == 2)
    {
        segs_t* seg1 = NULL;
        seg = &(field->ptr_seg[1]);
        value = (((uint32*)entry)[seg->word_offset]>>seg->start) & SHIFT_LEFT_MINUS_ONE(seg->bits);
        seg1 = &(field->ptr_seg[0]);
        value |= ((((uint32*)entry)[seg1->word_offset]>>seg1->start) & SHIFT_LEFT_MINUS_ONE(seg1->bits) )<< (seg->bits&0x1F);
    }
    else
    {
         drv_get_field(lchip, tbl_id, field_id, entry, &value);
    }

    return value;
}
/**
@brief Get a field  valued of a memory data entry
*/
uint32
drv_get_field_value(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id,  void* ds)
{
    uint32 value = 0;

    drv_get_field(lchip, tbl_id, field_id,                  ds, &value);
    return value;
}

uint32
drv_get_chip_type(uint8 lchip)
{
    if (lchip >= DRV_MAX_CHIP_NUM)
    {
        return MAX_DRV_CHIP;
    }
    return p_drv_master[lchip]->dev_type;
}
uint32
drv_get_chip_sub_type(uint8 lchip)
{
    if (lchip >= DRV_MAX_CHIP_NUM)
    {
        return DRV_CHIP_SUB_TYPE_MAX;
    }
    return p_drv_master[lchip]->dev_sub_type;
}

int32 drv_init_vchip(uint8 lchip, uint32 vchip_bmp, uint8 ldev)
{
    uint8 i = 0;
    uint8 vchip_num = 0;
    uint32 pp_bmp = 0;

    for (i = 0; i < DRV_MAX_PP_NUM; i++)
    {
        if (DRV_IS_BIT_SET(vchip_bmp, i))
        {
            drv_map_ldev[i + lchip]  = ldev;
            drv_vchip_pp_base[i + lchip] = lchip;
            DRV_BIT_SET(pp_bmp, (i + lchip) % 4);/*AT_TODO pp bmp in one core */
            vchip_num++;
        }
    }

    for (i = 0; i < DRV_MAX_PP_NUM; i++)
    {
        if (DRV_IS_BIT_SET(vchip_bmp, i))
        {
            drv_pcie_cmd_bmp[i + lchip] = pp_bmp;
            drv_vchip_pp_num[i + lchip] = vchip_num;
        }
    }

    return DRV_E_NONE;
}

uint8 drv_vchip_get_pp_base(uint8 lchip)
{
    return drv_vchip_pp_base[lchip];
}
uint8 drv_vchip_get_core_pp_base(uint8 lchip) /* AT_TODO */
{
    if (p_drv_master[lchip]->dev_type >= DRV_ARCTIC)
    {
#if (1 == SDK_WORK_PLATFORM)
    return (lchip >= (drv_vchip_pp_base[lchip] + 4))? (drv_vchip_pp_base[lchip] + 4) : drv_vchip_pp_base[lchip];
#endif
        switch (p_drv_master[lchip]->dev_sub_type)
        {
            case DRV_CHIP_SUB_TYPE_1:
            case DRV_CHIP_SUB_TYPE_2:
                return drv_vchip_pp_base[lchip];
            default :
                return (lchip >= (drv_vchip_pp_base[lchip] + p_drv_master[lchip]->core_pp_num))? 
                        (drv_vchip_pp_base[lchip] + p_drv_master[lchip]->core_pp_num) : drv_vchip_pp_base[lchip];
        }
    }
    else
    {
        return drv_vchip_pp_base[lchip];
    }
}
uint8 drv_vchip_get_pp_num(uint8 lchip)
{
    return drv_vchip_pp_num[lchip];
}
uint8 drv_vchip_get_pp_bmp(uint8 lchip)
{
#if defined(EMULATION_ENV) && !defined(EMULATOR_ENV)
    return (g_drv_oper_bmp >> 2) & 0xF;
#endif
    return ((1 << drv_vchip_pp_num[lchip]) - 1);
}
uint8 drv_vchip_get_core_num(uint8 lchip)
{
    return (drv_vchip_pp_num[lchip] / p_drv_master[lchip]->core_pp_num);
}
uint8 drv_vchip_get_core_pp_num(uint8 lchip)
{
    return p_drv_master[lchip]->core_pp_num;
}
uint8 drv_get_vchip_pcie_bmp(uint8 lchip)
{
    return drv_pcie_cmd_bmp[lchip];
}

STATIC int32
drv_ioctl_oam_api(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)
{
    uint8 action;
    int32 ret = 0;

    action = DRV_IOC_OP(cmd);

    if (DRV_IOC_WRITE == action)
    {
        DRV_MEP_LOCK(lchip);
        if (p_drv_master[lchip]->dev_type >= DRV_TSINGMA_MX)
        {

            ret = _drv_oam_mask_ioctl(lchip, index, cmd, oper_bmp, val);
        }
        else
        {
            ret = _drv_tm_oam_mask_ioctl(lchip, index, cmd, oper_bmp, val);
        }
        DRV_MEP_UNLOCK(lchip);
        return ret;
    }
    else
    {
       uint32  field_id = DRV_IOC_FIELDID(cmd);
       uint32 tbl_id = DRV_IOC_MEMID(cmd);
       if(DRV_ENTRY_FLAG == field_id)
       {
           return p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_READ](lchip,index, cmd, oper_bmp, val);
       }
       else
       {
          DsEthMep_m dsMep;
          ret = p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_READ](lchip, index, cmd, oper_bmp, (uint32*)&dsMep);
          ret = ret ?ret:drv_get_field(lchip, tbl_id, field_id, &dsMep, (uint32*)val);
          return ret;
       }
    }
      return 0;
}

int32
drv_usw_get_field_bits(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id, uint32* bits)
{
    fields_t* field = NULL;
    DRV_INIT_CHECK(lchip);
    DRV_TBL_ID_VALID_CHECK(lchip, tbl_id);
    field = TABLE_FIELD_INFO_PTR(lchip, tbl_id) + field_id;
    if (tbl_id != TABLE_INFO(lchip, tbl_id).tbl_id || field_id >= TABLE_FIELD_NUM(lchip, tbl_id) || 0 == field->bits)
    {
        DRV_DBG_INFO("ERROR! (drv_usw_mem_get_field): memID-%d, field-%d is not supported\n", tbl_id, field_id);
        return DRV_E_INVALID_FLD;
    }
    *bits = field->bits;
    return DRV_E_NONE;
}

int32
drv_field_ioctl_api(uint8 lchip, int32 index, uint64 cmd, void* val)
{
    tbls_id_t tbl_id;
    uint32 action;
     uint16 field_id;
    int32 ret = DRV_E_NONE;
    uint8 ioctl_type = 0;
    uint32* p_data_entry = NULL;
    uint8 dp_id = 0;
    uint8 oper_bmp = 0;
    uint8 read_oper_bmp = 0;

#ifndef SDK_IN_KERNEL
      uint32  data_entry[MAX_ENTRY_WORD];
      p_data_entry = data_entry;
#else
        p_data_entry = (uint32*)mem_malloc(MEM_SYSTEM_MODULE, sizeof(uint32)*MAX_ENTRY_WORD);
        if (!p_data_entry )
        {
            return DRV_E_NO_MEMORY;
        }
#endif
    action = DRV_IOC_OP(cmd);
    tbl_id = DRV_IOC_MEMID(cmd);
    field_id = DRV_IOC_FIELDID(cmd);
    dp_id = DRV_IOC_DP_ID(cmd);

    if ((tbl_id >= MaxTblId_t) || !p_drv_master[lchip]->init_done)
    {
        DRV_DBG_INFO("ERROR! TblID: %d, init state: %d line:%d function:%s\n",tbl_id, p_drv_master[lchip]->init_done, __LINE__,__FUNCTION__);
#ifdef SDK_IN_KERNEL
        mem_free(p_data_entry);
#endif
        return DRV_E_INVALID_PARAMETER;
    }
    if (p_drv_master[lchip]->dev_type >= DRV_ARCTIC)
    {
        oper_bmp = (cmd >> DRV_BITS_PER_WORD) & 0xFF;
        oper_bmp = (oper_bmp? (oper_bmp & (p_drv_master[lchip]->core_bmp[g_drv_chip[lchip].core_id][1] | p_drv_master[lchip]->pp_bmp[g_drv_chip[lchip].pp_id] | 3)):
                   g_drv_chip[lchip].def_bmp[!action]) & (p_drv_master[lchip]->oper_mask[TABLE_ENTRY_TYPE(lchip, tbl_id)]);
        DRV_OPER_BMP_MASK_PP(lchip, oper_bmp, tbl_id);
    }

    if (TABLE_MAX_INDEX(lchip, tbl_id) == 0)
    {
#ifdef SDK_IN_KERNEL
        if (p_data_entry)
        {
            mem_free(p_data_entry);
        }
#endif
          return 0;
    }
    ioctl_type = TABLE_IOCTL_TYPE(lchip, tbl_id);
    if(ioctl_type <= DRV_TBL_TYPE_TCAM )
    {
        if(action == DRV_IOC_WRITE)
        {
            read_oper_bmp = (p_drv_master[lchip]->core_bmp[g_drv_chip[lchip].core_id][1] | 
                            p_drv_master[lchip]->pp_bmp[g_drv_chip[lchip].pp_id] | p_drv_master[lchip]->dp_bmp[dp_id][1]);
            read_oper_bmp &= p_drv_master[lchip]->oper_mask[TABLE_ENTRY_TYPE(lchip, tbl_id)];
            DRV_OPER_BMP_MASK_PP(lchip, read_oper_bmp, tbl_id);
            DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[ioctl_type][DRV_IOC_READ](lchip, index, cmd, read_oper_bmp, p_data_entry), ret, out);
            DRV_IF_ERROR_GOTO(drv_set_field(lchip, tbl_id, field_id, p_data_entry, (uint32*)val), ret, out);
            DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[ioctl_type][DRV_IOC_WRITE](lchip, index, cmd, oper_bmp, p_data_entry), ret, out);
        }
        else
        {
            DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[ioctl_type][DRV_IOC_READ](lchip, index, cmd, oper_bmp, p_data_entry), ret, out);
            DRV_IF_ERROR_GOTO(drv_get_field(lchip, tbl_id, field_id, p_data_entry, (uint32*)val), ret, out);
        }
   }
   else
   {
        DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[ioctl_type][action](lchip, index, cmd, oper_bmp, val), ret, out);
   }
 out:
 #ifdef SDK_IN_KERNEL
    if (p_data_entry)
    {
        mem_free(p_data_entry);
    }
#endif
    return ret;
}

int32
drv_field_ioctl_bmp_api(uint8 lchip, int32 index, uint64 cmd, void* val)
{
    tbls_id_t tbl_id;
    uint32 action;
     uint16 field_id;
    int32 ret = DRV_E_NONE;
    uint8 ioctl_type = 0;
    uint32* p_data_entry = NULL;

    uint8 oper_bmp = 0;
    uint32  data_entry[MAX_ENTRY_WORD];
    p_data_entry = data_entry;

    action = DRV_IOC_OP(cmd);
    tbl_id = DRV_IOC_MEMID(cmd);

    oper_bmp = (cmd >> DRV_BITS_PER_WORD) & 0xFF;
    oper_bmp &= p_drv_master[lchip]->oper_mask[TABLE_ENTRY_TYPE(lchip, tbl_id)];
    DRV_OPER_BMP_MASK_PP(lchip, oper_bmp, tbl_id);
    field_id = DRV_IOC_FIELDID(cmd);

    DRV_TBL_ID_VALID_CHECK(lchip, tbl_id)
    if (0 == TABLE_FIELD_NUM(lchip, tbl_id) || TABLE_MAX_INDEX(lchip, tbl_id) == 0)
    {
          return 0;
    }
    ioctl_type = TABLE_IOCTL_TYPE(lchip, tbl_id);
    if(ioctl_type <= DRV_TBL_TYPE_TCAM)
    {
        if(action == DRV_IOC_WRITE)
        {
            DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[ioctl_type][DRV_IOC_READ](lchip, index, cmd, oper_bmp, p_data_entry), ret, out);
            DRV_IF_ERROR_GOTO(drv_set_field(lchip, tbl_id, field_id, p_data_entry, (uint32*)val), ret, out);
            DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[ioctl_type][DRV_IOC_WRITE](lchip, index, cmd, oper_bmp, p_data_entry), ret, out);
        }
        else
        {
            DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[ioctl_type][DRV_IOC_READ](lchip, index, cmd, oper_bmp, p_data_entry), ret, out);
            DRV_IF_ERROR_GOTO(drv_get_field(lchip, tbl_id, field_id, p_data_entry, (uint32*)val), ret, out);
        }
   }
   else
   {
        DRV_IF_ERROR_GOTO(p_drv_master[lchip]->ioctl_cb[ioctl_type][action](lchip, index, cmd, oper_bmp, val), ret, out);
   }
 out:

    return ret;
}

int32
drv_ioctl_api(uint8 lchip, uint32 index, uint64 cmd, void* val)
{
    tbls_id_t tbl_id;
    uint8 action;
    uint8 ioctl_type = 0;
    uint8 oper_bmp = 0;

    action = DRV_IOC_OP(cmd);
    tbl_id = DRV_IOC_MEMID(cmd);

    if ((tbl_id >= MaxTblId_t) || !p_drv_master[lchip]->init_done)
    {
        DRV_DBG_INFO("ERROR! TblID: %d, init state: %d line:%d function:%s\n",tbl_id, p_drv_master[lchip]->init_done, __LINE__,__FUNCTION__);
        return DRV_E_INVALID_PARAMETER;
    }
    if (p_drv_master[lchip]->dev_type >= DRV_ARCTIC)
    {
        oper_bmp = (cmd >> DRV_BITS_PER_WORD) & 0xFF;
        oper_bmp = (oper_bmp? (oper_bmp & (p_drv_master[lchip]->core_bmp[g_drv_chip[lchip].core_id][1] | p_drv_master[lchip]->pp_bmp[g_drv_chip[lchip].pp_id] | 3)):
                   g_drv_chip[lchip].def_bmp[!action]) & (p_drv_master[lchip]->oper_mask[TABLE_ENTRY_TYPE(lchip, tbl_id)]);
        DRV_OPER_BMP_MASK_PP(lchip, oper_bmp, tbl_id);
    }

    if (TABLE_MAX_INDEX(lchip, tbl_id) == 0)
    {
          return 0;
    }
    ioctl_type = TABLE_IOCTL_TYPE(lchip, tbl_id);

    return p_drv_master[lchip]->ioctl_cb[ioctl_type][action](lchip, index, cmd, oper_bmp, val);
}

int32
drv_ioctl_bmp_api(uint8 lchip, uint32 index, uint64 cmd, void* val)
{
    tbls_id_t tbl_id;
    uint32 action;
    uint8 ioctl_type = 0;
    uint8 oper_bmp = 0;

    action = DRV_IOC_OP(cmd);
    tbl_id = DRV_IOC_MEMID(cmd);

    if ((tbl_id >= MaxTblId_t) || !p_drv_master[lchip]->init_done)
    {
        DRV_DBG_INFO("ERROR! TblID: %d, init state: %d line:%d function:%s\n",tbl_id, p_drv_master[lchip]->init_done, __LINE__,__FUNCTION__);
        return DRV_E_INVALID_PARAMETER;
    }
    oper_bmp = (cmd >> DRV_BITS_PER_WORD) & 0xFF;
    oper_bmp &= p_drv_master[lchip]->oper_mask[TABLE_ENTRY_TYPE(lchip, tbl_id)];
    DRV_OPER_BMP_MASK_PP(lchip, oper_bmp, tbl_id);

    if (TABLE_MAX_INDEX(lchip, tbl_id) == 0)
    {
          return 0;
    }
    ioctl_type = TABLE_IOCTL_TYPE(lchip, tbl_id);

    return p_drv_master[lchip]->ioctl_cb[ioctl_type][action](lchip, index, cmd, oper_bmp, val);
}

int32
drv_ioctl_mcu_api(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)
{
#if(SDK_WORK_PLATFORM == 0)
    tbls_id_t tbl_id;
    uint32 action;
    action = DRV_IOC_OP(cmd);
    tbl_id = DRV_IOC_MEMID(cmd);
#endif

    DRV_INIT_CHECK(lchip);

#if(SDK_WORK_PLATFORM == 0)
    if (DRV_IOC_WRITE == action)
    {
        DRV_IF_ERROR_RETURN(drv_usw_mcu_tbl_lock(lchip, tbl_id, action));
    }
#endif
        DRV_IF_ERROR_RETURN(_drv_ioctl(lchip, index, cmd, oper_bmp, val));
#if(SDK_WORK_PLATFORM == 0)
    if (DRV_IOC_WRITE == action)
    {
        DRV_IF_ERROR_RETURN(drv_usw_mcu_tbl_unlock(lchip, tbl_id, action));
    }
#endif
    return DRV_E_NONE;
}

int32
drv_set_met_mode(uint8 lchip, uint8 met_ext_mode)
{
    p_drv_master[lchip]->met_ext_mode = met_ext_mode;
    return DRV_E_NONE;
}

#define PTP_PER_CORE_INDEX 93

STATIC int32
drv_ioctl_ptp_api(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)/*AT*/
{
    uint8 action = 0;
    action = DRV_IOC_OP(cmd);

    if (index < PTP_PER_CORE_INDEX)/*per core*/
    {
        oper_bmp &= p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_CORE];
    }
    else if (action == DRV_IOC_WRITE)
    {
        oper_bmp &= p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_CORE];
        oper_bmp |= (drv_pcie_cmd_bmp[lchip] << 2);
    }

    DRV_IF_ERROR_RETURN(_drv_ioctl(lchip, index, cmd, oper_bmp, val));
    return DRV_E_NONE;
}

STATIC int32
drv_ioctl_met_slim_api(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)/*AT*/
{
#define MET_1X_BYTE       20
#define MET_2X_BYTE       40
#define MET_3X_BYTE       60
#define MET_4X_BYTE       80
#define MET_SLIM1X_BYTE       12
#define MET_SLIM2X_BYTE       24
#define MET_SLIM3X_BYTE       36
#define MET_SLIM4X_BYTE          48

    uint32 ds_met_entry_max = TABLE_MAX_INDEX(lchip, DsMetEntry1X_t);
    uint8 action = 0;
    uint32 tbl_id = 0;

    action = DRV_IOC_OP(cmd);
    tbl_id = DRV_IOC_MEMID(cmd);
    if(2 == p_drv_master[lchip]->met_ext_mode)/*refer to sys_usw_nh_master_t.met_ext_mode, set by drv_set_met_mode*/
    {
        DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][action](lchip, index, cmd, oper_bmp, val));
    }
    else if (index >= ds_met_entry_max)
    {
        DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][action](lchip, (index - ds_met_entry_max), cmd, oper_bmp, val));
    }
    else
    {
        uint32 dsmet[20];
        uint32 tbl_id_map[] = {DsMetVector1X_t, DsMetVector2X_t, DsMetVector4X_t};
        uint32 entry_size = TABLE_ENTRY_SIZE(lchip, tbl_id);
        uint32 cmd1 = 0;
        tbl_id = tbl_id_map[(entry_size / MET_SLIM1X_BYTE) - 1];
        cmd1 = (cmd & (~(DRV_IOC_MEMID_MASK << DRV_IOC_MEMID_SHIFT))) + (tbl_id << DRV_IOC_MEMID_SHIFT);
        sal_memset(dsmet, 0, sizeof(dsmet));

        if (DRV_IOC_READ == action)/*5w mapping to 3w*/
        {
            DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][action](lchip, index, cmd1, oper_bmp, dsmet));
            sal_memcpy((uint8*)val, (uint8*)dsmet, MET_SLIM1X_BYTE);
            if (entry_size >= MET_SLIM2X_BYTE)
            {
                sal_memcpy(((uint8*)val) + MET_SLIM1X_BYTE, ((uint8*)dsmet) + MET_1X_BYTE, MET_SLIM1X_BYTE);
            }
            if (entry_size >= MET_SLIM4X_BYTE)
            {
                sal_memcpy(((uint8*)val) + MET_SLIM2X_BYTE, ((uint8*)dsmet) + MET_2X_BYTE, MET_SLIM1X_BYTE);
                sal_memcpy(((uint8*)val) + MET_SLIM3X_BYTE, ((uint8*)dsmet) + MET_3X_BYTE, MET_SLIM1X_BYTE);
            }
        }
        else/*3w mapping to 5w*/
        {
            sal_memcpy((uint8*)dsmet, (uint8*)val, MET_SLIM1X_BYTE);
            if (entry_size >= MET_SLIM2X_BYTE)
            {
                sal_memcpy(((uint8*)dsmet) + MET_1X_BYTE,((uint8*)val) + MET_SLIM1X_BYTE,  MET_SLIM1X_BYTE);
            }
            if (entry_size >= MET_SLIM4X_BYTE)
            {
                sal_memcpy(((uint8*)dsmet) + MET_2X_BYTE,((uint8*)val) + MET_SLIM2X_BYTE,  MET_SLIM1X_BYTE);
                sal_memcpy(((uint8*)dsmet) + MET_3X_BYTE, ((uint8*)val) + MET_SLIM3X_BYTE, MET_SLIM1X_BYTE);
            }
            DRV_IF_ERROR_RETURN(p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][action](lchip, index, cmd1, oper_bmp, dsmet));
        }
    }

    return DRV_E_NONE;
}

STATIC int32
drv_ioctl_multi_core_api(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)/*AT*/
{    
    uint32 max_idx = 0;
    uint32 local_index = 0;
    uint8 _dual_core_lchip = 0;
    uint8 _core_pp_num = p_drv_master[lchip]->core_pp_num;
    uint8 _pp_id = lchip - drv_vchip_pp_base[lchip];

    DRV_IF_ERROR_RETURN(_drv_ioctl(lchip, index, cmd, oper_bmp, val));

    if (DRV_IOC_READ == DRV_IOC_OP(cmd))
    {
        return DRV_E_NONE;
    }
    /* convert to cross core pp_id */
    _dual_core_lchip = (_pp_id >= _core_pp_num) ? (lchip - _core_pp_num) : (lchip + _core_pp_num);    
    max_idx = TABLE_MAX_INDEX(lchip, DRV_IOC_MEMID(cmd));
    local_index = max_idx / TABLE_ADDR_NUM(lchip,  DRV_IOC_MEMID(cmd));
    local_index = (index >>24) * local_index + (index & 0xFFFFFF);

    /* swap core 0 and core 1 bit */
    oper_bmp = (((oper_bmp>>DRV_CMD_CORE_BMP_SHIFT) & 0x3) == 0x3) ? oper_bmp : (oper_bmp ^ (0x3<<DRV_CMD_CORE_BMP_SHIFT));
    DRV_IF_ERROR_RETURN(_drv_ioctl(_dual_core_lchip, (local_index + (max_idx >> 1)) % max_idx,  cmd, oper_bmp, val));

    return DRV_E_NONE;
}

STATIC int32
drv_ioctl_single_core_api(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)/*AT*/
{
    DRV_IF_ERROR_RETURN(_drv_ioctl(lchip, index, cmd, oper_bmp, val));

    return DRV_E_NONE;
}

STATIC int32
drv_ioctl_channel_map_api(uint8 lchip, uint32 index, uint32 cmd, uint8 oper_bmp, uint32* val)/*TMG*/
{
    uint32 action;
    int32 ret;

    index = ((index&0x3f) | ((index&0x40)<<1) | (index&0x80));

    action = DRV_IOC_OP(cmd);
    /*all tbl is static*/
    ret = p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][action](lchip, index, cmd, oper_bmp, val);

    return ret;
}

/**
  @driver Driver Acc Api
*/
int32
drv_acc_api(uint8 lchip, void* in, void* out)
{
     drv_acc_in_t* p_acc = (drv_acc_in_t*)in;
#if (SDB_MEM_MODEL == SDB_MODE)
     if (p_drv_master[lchip]->dev_type < DRV_TSINGMA_MX)
     {
         return DRV_E_NONE;
     }
#endif
     return p_drv_master[lchip]->drv_acc_cb[p_acc->module](lchip, p_acc->module, in, out);
}

int32
drv_usw_register_eunit_lock(uint8 lchip, void* cb)
{
    DRV_INIT_CHECK(lchip);

    p_drv_master[lchip]->eunit_lock_cb = cb;

    return DRV_E_NONE;
}

int32
drv_usw_set_eunit_lock_en(uint8 lchip, uint8 enable)
{
    DRV_INIT_CHECK(lchip);
    FIB_ACC_LOCK(lchip);

    p_drv_master[lchip]->eunit_lock_en = enable;

    FIB_ACC_UNLOCK(lchip);

    return DRV_E_NONE;
}

/**
  @driver Driver Get ChipAgent mode
*/
int32
drv_get_chip_agent_mode(void)
{
        return 0;
}

/**
  @driver Driver Set warmboot status
*/
int32
drv_set_warmboot_status(uint8 lchip, uint32 wb_status)
{
    DRV_INIT_CHECK(lchip);

    p_drv_master[lchip]->wb_status = wb_status;

    return DRV_E_NONE;
}

int32
drv_get_warmboot_status(uint8 lchip, uint32* p_wb_status)
{
    DRV_INIT_CHECK(lchip);

    *p_wb_status = p_drv_master[lchip]->wb_status;

    return DRV_E_NONE;
}

#ifdef DUET2
extern int32
drv_tbls_list_init_duet2(uint8 lchip);
int32
drv_tbls_list_deinit_duet2(uint8 lchip);
#endif

#ifdef TSINGMA
extern int32
drv_tbls_list_init_tsingma(uint8 lchip);
int32
drv_tbls_list_deinit_tsingma(uint8 lchip);
#endif



#if defined(TSINGMA_MX)
extern int32
drv_tbls_list_init_tmm(uint8 lchip);
int32
drv_tbls_list_deinit_tmm(uint8 lchip);
#endif

#if defined(TSINGMA_GX)
extern int32
drv_tbls_list_init_tmg(uint8 lchip);
int32
drv_tbls_list_deinit_tmg(uint8 lchip);
#endif


#ifdef ARCTIC
extern int32
drv_tbls_list_init_at(uint8 lchip);
int32
drv_tbls_list_deinit_at(uint8 lchip);
#endif

int32
drv_tbls_info_init(uint8 lchip)
{
    uint32 dev_id = 0;

    dal_get_chip_dev_id(DRV_MAP_LDEV(lchip), &dev_id);

#ifdef DUET2
    if (dev_id == DAL_DUET2_DEVICE_ID)
    {
        drv_tbls_list_init_duet2(lchip);
    }
#endif


#ifdef TSINGMA
    if (dev_id == DAL_TSINGMA_DEVICE_ID)
    {
        drv_tbls_list_init_tsingma(lchip);
    }
#endif

#if defined(TSINGMA_MX)

    if (dev_id == DAL_TSINGMA_MX_DEVICE_ID)
    {
        drv_tbls_list_init_tmm(lchip);
    }
#endif

#if defined(TSINGMA_GX)
    
        if (dev_id == DAL_TSINGMA_GX_DEVICE_ID)
        {
            drv_tbls_list_init_tmg(lchip);
        }
#endif


#ifdef ARCTIC

    if (dev_id == DAL_ARCTIC_DEVICE_ID)
    {
        drv_tbls_list_init_at(lchip);
    }
#endif

    return 0;
}

int32
drv_tbls_info_deinit(uint8 lchip)
{

#ifdef DUET2
    if (DRV_IS_DUET2(lchip))
    {
        drv_tbls_list_deinit_duet2(lchip);
    }
#endif


#ifdef TSINGMA

    if (DRV_IS_TSINGMA(lchip))
    {
        drv_tbls_list_deinit_tsingma(lchip);
    }
#endif

#if defined(TSINGMA_MX)

    if (DRV_IS_TMM(lchip))
    {
        drv_tbls_list_deinit_tmm(lchip);
    }
#endif

#if defined(TSINGMA_GX)
    
        if (DRV_IS_TMG(lchip))
        {
            drv_tbls_list_deinit_tmg(lchip);
        }
#endif


#ifdef ARCTIC

    if (DRV_IS_AT(lchip))
    {
        drv_tbls_list_deinit_at(lchip);
    }
#endif

    return 0;
}
#if  (SDK_WORK_PLATFORM == 1)
extern int32
drv_model_common_init(uint8 lchip);

 #endif

#if (SDK_WORK_PLATFORM == 0)
static int32
_drv_usw_pci_read_chip(uint8 lchip, uint32 offset, uint32 len, uint32* p_value)
{
    drv_pci_cmd_status_u_t cmd_status_u;
    uint32 timeout = DRV_CMD_TIMEOUT;
    uint8 index = 0;

    /* 1. write CmdStatusReg */
    cmd_status_u.val = 0;
    cmd_status_u.cmd_status.cmdReadType = 1;
    cmd_status_u.cmd_status.cmdEntryWords = (len==16)?0:len;   /* normal operate only support 1 entry */
    cmd_status_u.cmd_status.cmdDataLen = len;
    g_dal_op.pci_write(lchip, DRV_PCI_CMD_STATUS, cmd_status_u.val);

    /* 2. write AddrReg */
    g_dal_op.pci_write(lchip, DRV_PCI_ADDR, offset);

    /* 3. polling status and check */
    g_dal_op.pci_read(lchip, DRV_PCI_CMD_STATUS, &cmd_status_u.val);
    while (!(cmd_status_u.cmd_status.reqProcDone) && (--timeout))
    {
        g_dal_op.pci_read(lchip, DRV_PCI_CMD_STATUS, &cmd_status_u.val);
    }

    /* 4. read data from buffer */
    for (index = 0; index < len; index++)
    {
        g_dal_op.pci_read(lchip, DRV_PCI_DATA_BUF + (index << 2), p_value + index);
    }

    return DRV_E_NONE;
}

 #endif

/**
  @driver Driver Init Api,per chip init TBD
*/
#ifdef EMULATION_ENV
uint32 g_drv_oper_bmp = 0xFF;

#define MASK_BMP_FOR_EMU(index, tbl_id, new_index) \
    do{\
        if(TABLE_ENTRY_TYPE(0, tbl_id) == MEM_TYPE_PER_CORE)\
        {\
            if (((bmp >> 6) & 0x3) == 0)\
            {\
                new_index = 0xFFFFFFFF;\
            }\
        }\
        else if (TABLE_ENTRY_TYPE(0, tbl_id) == MEM_TYPE_PER_PP || TABLE_ENTRY_TYPE(0, tbl_id) == MEM_TYPE_PEER_PP)\
        {\
            if (((bmp >> 6) & 0x3) == 0 || ((bmp >> 2) & 0xF) == 0)\
            {\
                new_index = 0xFFFFFFFF;\
            }\
        }\
        else if (TABLE_ENTRY_TYPE(0, tbl_id) == MEM_TYPE_PER_DP || TABLE_ENTRY_TYPE(0, tbl_id) == MEM_TYPE_PEER_DP)\
        {\
            if (((bmp >> 6) & 0x3) == 0 || ((bmp >> 2) & 0xF) == 0 || (bmp & 0x3) == 0)\
            {\
                new_index = 0xFFFFFFFF;\
            }\
        }\
    }while(0);

int32
drv_usw_emul_load_config(uint8 lchip, char* p_file_name, uint8 check_en)
{
    int32 ret = 0;
    uint64 bmp = 0;
    uint8 line[512] = {0};
    uint32 chip_id = 0, data = 0, tbl_id = 0;
    uint64 index = 0, index1 = 0, offset = 0, new_index;
    char tbl_name[64] = {0};
    char cfg_file_ptr[256] = {0};
    sal_file_t cfg_fp = NULL;
    sal_file_t failed_addr = NULL;

    if (!p_file_name)
    {
        return DRV_E_INVALID_PTR;
    }
    /* Open Each Configuration File */
    cfg_fp = sal_fopen((char *)p_file_name, "r");
    if(NULL == cfg_fp)
    {
        DRV_DUMP_INFO("%% File <%s> can't open or not exist!\n", cfg_file_ptr);
        return DRV_E_INVALID_PTR;
    }

    if (check_en)
    {
        failed_addr = sal_fopen("failed_addr.txt", "w");
        if (NULL == failed_addr)
        {
            sal_fclose(cfg_fp);
            DRV_DBG_INFO("%% File failed_addr.txt can't open or not exist!\n");
            return DRV_E_INVALID_PTR;
        }
    }

    /* per-record operations, until no record in configurations file */
    sal_memset(line, 0, 512);

    while (NULL != sal_fgets((char *)line, 512, cfg_fp))
    {
        ret = 0;
        chip_id = 0;
        offset = 0;
        data = 0;
        sal_memset(tbl_name,'\0',sizeof(char) << 6);
        tbl_id = 0;
        index = 0;
        index1 = 0;

        if('#' == line[0] || 7 != sal_sscanf((char *)line, "%d %lx %x #%s %d [%ld/%lx]", &chip_id, &offset, &data, tbl_name, &tbl_id, &index, &index1))
        {
            continue;
        }
        bmp = (index >> 32);
        bmp &= g_drv_oper_bmp;
        new_index = (bmp << 32) | (offset & 0xFFFFFFFF);
        if (check_en)
        {
            MASK_BMP_FOR_EMU(index, tbl_id, new_index);
            if (new_index == 0xFFFFFFFF)
            {
                continue;
            }
        }

        ret = drv_usw_chip_write(0, new_index, data);
        if (ret != DRV_E_NONE)
        {
            if (check_en)
            {
                sal_fprintf(failed_addr, (char *)line);
            }
            DRV_DBG_INFO("%% Emulation load config file<%s> chip<%d> err<%d>faild!\n", cfg_file_ptr, chip_id, ret);
            DRV_DBG_INFO("%% Write chip<%d> offset<0x%08x> data<0x%08x> err<%d> faild!\n", chip_id, offset, data, ret);
        }
    }

    sal_fclose(cfg_fp);
    if (check_en)
    {
        sal_fclose(failed_addr);
    }

    return DRV_E_NONE;
}
#endif

int32
drv_device_identify(uint8 lchip)
{
    if(DRV_IS_TSINGMA(lchip))
    {
        int32 ret = 0;
        uint32 efuse_value[2] = {0};
        uint32 part_number1[2]  = {0x35313138, 0x43544320};
        uint32 part_number2[2]  = {0x35313139, 0x43544320};
        uint32 part_number3[2]  = {0x33313234, 0x43544320};
        uint32 part_number4[2]  = {0x33313235, 0x43544320};
        uint32 part_number5[2]  = {0x37313138, 0x43544320};
        uint32 part_number6[2]  = {0x31313854, 0x43544335};
        ret = drv_read_efuse_data(lchip, 16, 2, efuse_value);
        if(efuse_value[0] && (0 == ret) && (!sal_memcmp(efuse_value, part_number3, sizeof(part_number3)) || !sal_memcmp(efuse_value, part_number1, sizeof(part_number1)) ||
          !sal_memcmp(efuse_value, part_number2, sizeof(part_number2)) || !sal_memcmp(efuse_value, part_number4, sizeof(part_number4)) ||
          !sal_memcmp(efuse_value, part_number6, sizeof(part_number6))))
        {
            p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_1;
        }
        else if(efuse_value[0] && (0 == ret) && (!sal_memcmp(efuse_value, part_number5, sizeof(part_number5))))
        {
            p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_2;
        }
    }
    else if((DRV_IS_TMM(lchip) || DRV_IS_TMG(lchip)))
    {
        int32 ret = 0;
        uint32 efuse_value[2] = {0};
        uint32 part_number1[2]  = {0x38313831, 0x43544320};
        uint32 part_number2[2]  = {0x38313832, 0x43544320};
        uint32 part_number4[2]  = {0x38313836, 0x43544320};
        ret = drv_read_efuse_data(lchip, 16, 2, efuse_value);
        if(efuse_value[0] && (0 == ret) )
        {
            if(!sal_memcmp(efuse_value, part_number1, sizeof(part_number1)) )
            {
                p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_1;
            }
            else if(!sal_memcmp(efuse_value, part_number2, sizeof(part_number2)))
            {
                p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_2;
            }
            else if(!sal_memcmp(efuse_value, part_number4, sizeof(part_number4)))
            {
                p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_4;
           }
        }
    }
    else if (DRV_IS_AT(lchip))
    {
        uint32 product_number = 0;

        (void)drv_usw_chip_read(lchip, 0x00890320, &product_number);  /* tbl ChipPartNumber */
        
        #if (SDK_WORK_PLATFORM == 1 || (SDB_MEM_MODEL == SDB_MODE))
        product_number = 9;
        #endif     


        switch (product_number)
        {
        case 2:
            p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_1;  /* CTC9260 */
            break;
        case 4:
            p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_2;  /* CTC9262 */
            break;
        case 9:
            p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_3;  /* CTC9280 */
            break;
        case 12:
            p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_4;  /* CTC9282 */
            break;
        }
    }

#ifdef EMULATOR_ENV
        p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_0;
#elif defined(EMULATION_ENV)
        p_drv_master[lchip]->dev_sub_type = DRV_CHIP_SUB_TYPE_0;
#endif

    return DRV_E_NONE;
}

int32
drv_init_bmp_mask(uint8 lchip)
{
    uint8 core_num = 0;
    uint8 pp_num = 0;
    uint8 core_id = 0;
    uint8 pp_id = 0;

    pp_num = dal_device_get_pp_num(DRV_MAP_LDEV(lchip));
    core_num = 1;
    
    if (p_drv_master[lchip]->dev_type == DRV_ARCTIC)
    {
        if (DRV_CHIP_SUB_TYPE_2 == p_drv_master[lchip]->dev_sub_type)
        {
            /*CTC9262:1core 3pp*/
            core_num = 1;
        }
        else if (DRV_CHIP_SUB_TYPE_1 == p_drv_master[lchip]->dev_sub_type)
        {
            /*CTC9260:1core 4pp*/    
            core_num = 1;
        }
        else if (DRV_CHIP_SUB_TYPE_4 == p_drv_master[lchip]->dev_sub_type)
        {
            /*CTC9282:2core 6pp*/
            core_num = 2;
        }
        else
        {        
            /*CTC9282:2core 8pp*/
            core_num = 2;
        }
#ifdef EMULATION_ENV
        DRV_CONST(DRV_DMA_TCAM_SCAN_DESC_NUM) = 20*2;
#else
        DRV_CONST(DRV_DMA_TCAM_SCAN_DESC_NUM) = 53*(pp_num/core_num);
#endif
    }

    p_drv_master[lchip]->core_pp_num = pp_num/core_num;
    for (core_id = 0; core_id < core_num; core_id++)
    {
        /* encap core level oper mask*/
        p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_CORE] |= 1<<(DRV_CORE_BMP_START+core_id); 
        for (pp_id = 0; pp_id < p_drv_master[lchip]->core_pp_num; pp_id++)
        {
            /* encap pp level oper mask*/
            p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_PP] |= 1 << (DRV_PP_BMP_START+pp_id);
            p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_PP] |= 1 << (DRV_PP_BMP_START+pp_id);
        }
        p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_PP] |= p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_CORE];
        p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_PP] |= p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_CORE];

        /*encap dp level oper mask*/
        p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_DP] = p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_PP] | 0x3;
        p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_DP] = p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_PP] | 0x3;
    }

    return DRV_E_NONE;
}

int32
drv_show_status(uint8 lchip)
{    
    if(p_drv_master[lchip] == NULL || !p_drv_master[lchip]->init_done)
    {
        return DRV_E_NONE;
    }

    DRV_DUMP_INFO("lchip%u status:\n", lchip);
    DRV_DUMP_INFO("----------------------------------------\n");
    DRV_DUMP_INFO("%-15s%-3s%-4u\n", "dev_type",            ":", p_drv_master[lchip]->dev_type);
    DRV_DUMP_INFO("%-15s%-3s%-4u\n", "dev_sub_type",        ":", p_drv_master[lchip]->dev_sub_type);
    DRV_DUMP_INFO("%-15s%-3s%-4u\n", "ldev",                ":", drv_map_ldev[lchip]);
    DRV_DUMP_INFO("%-15s%-3s%-4u\n", "pp_base",             ":", g_drv_master[lchip].pp_base);
    DRV_DUMP_INFO("%-15s%-3s%-4u\n", "pp_num",              ":", drv_vchip_pp_num[lchip]);
    DRV_DUMP_INFO("%-15s%-3s%-4u\n", "core_id",             ":", g_drv_chip[lchip].core_id);
    DRV_DUMP_INFO("%-15s%-3s%-4u\n", "pp_id",               ":", g_drv_chip[lchip].pp_id);
    DRV_DUMP_INFO("%-15s%-3s0x%-4x\n", "def_bmp",           ":", g_drv_chip[lchip].def_bmp[1]);
    DRV_DUMP_INFO("%-15s%-3s0x%-4X\n", "core_op_bmp",       ":", p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_CORE]);
    DRV_DUMP_INFO("%-15s%-3s0x%-4x\n", "pp_op_bmp",         ":", p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_PP]);
    DRV_DUMP_INFO("%-15s%-3s0x%-4x\n", "peer_pp_op_bmp",    ":", p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_PP]);
    DRV_DUMP_INFO("%-15s%-3s0x%-4x\n", "dp_op_bmp",         ":", p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_DP]);
    DRV_DUMP_INFO("%-15s%-3s0x%-4x\n", "peer_dp_op_bmp",    ":", p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_DP]);
    DRV_DUMP_INFO("----------------------------------------\n");
    
    return DRV_E_NONE;
}


int32
drv_init(uint8 lchip, uint8 base)
{
    uint32 dev_id = 0;
    uint8 cnt = 0;
#if (SDK_WORK_PLATFORM == 0)
    uint32 value = 0;
#endif

    if (lchip >= DRV_MAX_CHIP_NUM)
    {
        return DRV_E_INVALID_CHIP;
    }

    if(p_drv_master[lchip] == NULL || !p_drv_master[lchip]->init_done)
    {
        sal_memset(&g_drv_master[lchip], 0, sizeof(drv_master_t));
        p_drv_master[lchip] = &(g_drv_master[lchip]);
    }

    {
        uint16 core_pp_num = 0;

        g_drv_master[lchip].pp_base = drv_vchip_pp_base[lchip];
        core_pp_num = (drv_vchip_pp_num[lchip]>(DRV_MAX_PP_NUM>>1))?(drv_vchip_pp_num[lchip]>>1):drv_vchip_pp_num[lchip];
        g_drv_chip[lchip].pp_id = (lchip - p_drv_master[drv_vchip_get_pp_base(lchip)]->pp_base) % core_pp_num;
        g_drv_chip[lchip].core_id =(lchip - p_drv_master[drv_vchip_get_pp_base(lchip)]->pp_base) / core_pp_num;
        g_drv_chip[lchip].def_bmp[0] = 0xFF;
        g_drv_chip[lchip].def_bmp[1] = (((1<<g_drv_chip[lchip].core_id)<<6) | ((1<<g_drv_chip[lchip].pp_id)<<2) | 1);
    }
    dal_get_chip_dev_id(DRV_MAP_LDEV(lchip), &(dev_id));
#if (SDK_WORK_PLATFORM == 1)
    if ((DAL_ARCTIC_DEVICE_ID == dev_id) && (drv_vchip_pp_num[lchip] > (DRV_MAX_PP_NUM>>1)) 
        && (drv_vchip_get_pp_num(lchip) == (DRV_MAX_PP_NUM>>1)))
    {
        g_drv_vchip_mode = 1;
    }
    if (lchip && g_drv_vchip_mode)
    {
        return DRV_E_NONE;
    }
#endif
    if (lchip != drv_vchip_get_pp_base(lchip))
    {
        p_drv_master[lchip] = p_drv_master[drv_vchip_get_pp_base(lchip)];
        return DRV_E_NONE;
    }

    p_drv_master[lchip]->plaform_type = SDK_WORK_PLATFORM;
    p_drv_master[lchip]->workenv_type = SDK_WORK_ENV;
    p_drv_master[lchip]->access_type = DRV_PCI_ACCESS;
    p_drv_master[lchip]->dev_virt_addr = dal_get_dev_addr(DRV_MAP_LDEV(lchip));

    /*For AT, TODO*/
    p_drv_master[lchip]->dp_bmp[0][0] = 0x3;
    p_drv_master[lchip]->dp_bmp[0][1] = 0x1;
    p_drv_master[lchip]->dp_bmp[1][0] = 0x3;
    p_drv_master[lchip]->dp_bmp[1][1] = 0x2;

    p_drv_master[lchip]->core_bmp[0][0] = 0x3 << 6;
    p_drv_master[lchip]->core_bmp[0][1] = 0x1 << 6;
    p_drv_master[lchip]->core_bmp[1][0] = 0x3 << 6;
    p_drv_master[lchip]->core_bmp[1][1] = 0x2 << 6;

    for (cnt = 0; cnt < 4; cnt++)
    {
        p_drv_master[lchip]->pp_bmp[cnt] = (1 << cnt) << 2;
    }
#ifdef EMULATION_ENV
{
    sal_file_t local_fp = NULL;
    char buffer[512] = {0};
    char* p_str;
    uint8 _loop_tmp = 0;

    local_fp = sal_fopen("pp.info", "r");
    if (local_fp)
    {
        while (NULL != sal_fgets(buffer, 512, local_fp))
        {
            /*comment line*/
            if ('#' == buffer[0])
            {
                continue;
            }
            /*OPER_BMP: bit0-1: dp_bmp; bit2-5: pp_bmp; bit6-7: core_bmp*/
            if ((NULL != (p_str = sal_strstr(buffer, "OPER_BMP"))) && sal_strstr(buffer, "[") && sal_strstr(buffer, "]"))
            {
                if (NULL != (p_str = sal_strstr(buffer, "=")))
                {
                    g_drv_oper_bmp = (uint8)sal_strtol(p_str + 1, NULL, 0);
                }
                break;
            }
        }
        sal_fclose(local_fp);
    }
    /*2pp*/
    p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_CORE] = 0xC0;
    p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_PP] = 0xFC;
    p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_PP] = 0xFC;
    p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_DP] = 0xFF;
    p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_DP] = 0xFF;

    p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_DP] &= g_drv_oper_bmp;
    p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_PP] &= g_drv_oper_bmp;
    p_drv_master[lchip]->oper_mask[MEM_TYPE_PER_CORE] &= g_drv_oper_bmp;
    p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_DP] &= g_drv_oper_bmp;
    p_drv_master[lchip]->oper_mask[MEM_TYPE_PEER_PP] &= g_drv_oper_bmp;
    g_drv_emu_first_pp_bmp = 0;
    for (_loop_tmp = 0; _loop_tmp < 4; _loop_tmp++)
    {
        if (DRV_IS_BIT_SET(g_drv_oper_bmp >> 2, _loop_tmp))
        {
            DRV_BIT_SET(g_drv_emu_first_pp_bmp, _loop_tmp + 2);
            break;
        }
    }
}
#endif

    if (dev_id == DAL_DUET2_DEVICE_ID)
    {
        p_drv_master[lchip]->dev_type = DRV_DUET2;
    }
    else if (dev_id == DAL_TSINGMA_DEVICE_ID)
    {
        p_drv_master[lchip]->dev_type = DRV_TSINGMA;
    }
    else if (dev_id == DAL_TSINGMA_MX_DEVICE_ID)
    {
        p_drv_master[lchip]->dev_type = DRV_TSINGMA_MX;
    }
    else if (dev_id == DAL_TSINGMA_GX_DEVICE_ID)
    {
        p_drv_master[lchip]->dev_type = DRV_TSINGMA_GX;
    }
    else
    {
        p_drv_master[lchip]->dev_type = DRV_ARCTIC;
    }

    if (p_drv_master[lchip]->access_type == DRV_PCI_ACCESS)
    {
        p_drv_master[lchip]->drv_chip_read_ext = g_dal_op.pci_read_ext2;/*with mask*/
        p_drv_master[lchip]->drv_chip_write_ext = g_dal_op.pci_write_ext2;  /*with mask*/
        p_drv_master[lchip]->drv_chip_read = g_dal_op.pci_read_ext;
        p_drv_master[lchip]->drv_chip_write = g_dal_op.pci_write_ext;

#if (SDK_WORK_PLATFORM == 0)
        if (dev_id == DAL_DUET2_DEVICE_ID)
        {
            _drv_usw_pci_read_chip(lchip, 0x0, 1, &value);
        }
#endif
    }
    else if (p_drv_master[lchip]->access_type == DRV_I2C_ACCESS)
    {
        p_drv_master[lchip]->drv_chip_read = drv_usw_i2c_read_chip;
        p_drv_master[lchip]->drv_chip_write = drv_usw_i2c_write_chip;
        p_drv_master[lchip]->drv_chip_read_ext = drv_usw_i2c_read_chip_ext;
       p_drv_master[lchip]->drv_chip_write_ext = drv_usw_i2c_write_chip;
    }

    _drv_get_host_type(lchip);
    drv_tbls_info_init(lchip);

    if (p_drv_master[lchip]->dev_type >= DRV_TSINGMA_MX)
    {
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_READ] = drv_usw_chip_sram_tbl_read2;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_WRITE] = drv_usw_chip_sram_tbl_write2;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_READ] = drv_usw_chip_dyn_tbl_read2;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_WRITE] = drv_usw_chip_dyn_tbl_write2;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_HOOK][DRV_IOC_READ] = drv_usw_chip_sram_tbl_read2;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_HOOK][DRV_IOC_WRITE] = drv_usw_chip_sram_tbl_write3;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_HOOK][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_MASK][DRV_IOC_READ] = drv_usw_chip_dyn_tbl_read2;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_MASK][DRV_IOC_WRITE] = drv_usw_chip_dyn_tbl_mask_write2;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_MASK][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_M_CORE][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_LPM][DRV_IOC_READ] = drv_usw_chip_dyn_tbl_read2;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_LPM][DRV_IOC_WRITE] = drv_usw_chip_dyn_tbl_lpm;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_CHA_MAP][DRV_IOC_WRITE] = drv_ioctl_channel_map_api;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_CHA_MAP][DRV_IOC_READ] = drv_ioctl_channel_map_api;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_CHA_MAP][DRV_IOC_REMOVE] = drv_ioctl_channel_map_api;
    }
    else
    {
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_READ] = drv_usw_chip_sram_tbl_read;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_WRITE] = drv_usw_chip_sram_tbl_write;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_NORMAL][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_READ] = drv_usw_chip_dyn_tbl_read;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_WRITE] = drv_usw_chip_dyn_tbl_write;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_LPM][DRV_IOC_READ] = drv_usw_chip_dyn_tbl_read;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_LPM][DRV_IOC_WRITE] = drv_usw_chip_lpm_tbl_write;

        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_MASK][DRV_IOC_READ] = drv_usw_chip_dyn_tbl_read;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_MASK][DRV_IOC_WRITE] = drv_usw_chip_dyn_tbl_write;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_MASK][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null;
    }
    p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_DYN_LPM][DRV_IOC_REMOVE] = drv_usw_chip_sram_tbl_null; 
    p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_TCAM][DRV_IOC_READ] = drv_usw_chip_tcam_tbl_read;
    p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_TCAM][DRV_IOC_WRITE] = drv_usw_chip_tcam_tbl_write;
    p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_TCAM][DRV_IOC_REMOVE] = drv_usw_chip_tcam_tbl_remove;

     for (cnt = 0; cnt < DRV_IOC_MAX; cnt++)
    {
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_OAM][cnt] = drv_ioctl_oam_api;
    #if (SDK_WORK_PLATFORM == 0)
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_APS_MASK][cnt] = drv_ioctl_aps_mask_api;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_MAC][cnt] = drv_ioctl_drain_dis_api;
    #endif
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_MCU][cnt] = drv_ioctl_mcu_api;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_MET_SLIM][cnt] = drv_ioctl_met_slim_api;
        p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_RTC][cnt] = drv_ioctl_ptp_api;
    }

#if (defined(DUET2) || defined(TSINGMA)) && (SDK_WORK_PLATFORM == 1)
    drv_model_common_init(lchip);
#else
    drv_chip_common_init(lchip);
#endif
#if (1 == SDK_WORK_PLATFORM)
    dal_init_sim_io_cb(lchip);
#endif
    p_drv_master[lchip]->init_done = 1;
    drv_usw_acc_init(lchip);

    drv_device_identify(lchip);

    drv_init_bmp_mask(lchip);

    if (p_drv_master[lchip]->dev_type == DRV_ARCTIC)
    {
        if (drv_vchip_pp_num[lchip] > p_drv_master[lchip]->core_pp_num)
        {
            p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_M_CORE][DRV_IOC_READ] = drv_ioctl_multi_core_api;
            p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_M_CORE][DRV_IOC_WRITE] = drv_ioctl_multi_core_api;
        }
        else
        {
            p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_M_CORE][DRV_IOC_READ] = drv_ioctl_single_core_api;
            p_drv_master[lchip]->ioctl_cb[DRV_TBL_TYPE_M_CORE][DRV_IOC_WRITE] = drv_ioctl_single_core_api;
        }
    }


    return DRV_E_NONE;
}

int32
drv_deinit(uint8 lchip, uint8 base)
{
    uint8 pp_base = drv_vchip_get_pp_base(lchip);
    uint8 pp_num  = drv_vchip_get_pp_num(lchip);

    if (DRV_FROM_AT(lchip) && (lchip != (pp_base+pp_num-1)))
    {
        sal_memset(&(g_drv_chip[lchip]), 0, sizeof(drv_chip_info_t));
        return DRV_E_NONE;
    }
#if (SDK_WORK_PLATFORM == 1)
    if (g_drv_vchip_mode && !lchip)
    {
        return DRV_E_NONE;
    }
#endif
    drv_ser_deinit(lchip);
    drv_tbls_info_deinit(lchip);

    p_drv_master[lchip]->fib_acc_mutex ? sal_mutex_destroy(p_drv_master[lchip]->fib_acc_mutex):0;
    p_drv_master[lchip]->cpu_acc_mutex ? sal_mutex_destroy(p_drv_master[lchip]->cpu_acc_mutex):0;
    p_drv_master[lchip]->ipfix_acc_mutex ? sal_mutex_destroy(p_drv_master[lchip]->ipfix_acc_mutex):0;
    p_drv_master[lchip]->cid_acc_mutex ? sal_mutex_destroy(p_drv_master[lchip]->cid_acc_mutex):0;
#ifndef PACKET_TX_USE_SPINLOCK
    p_drv_master[lchip]->p_entry_mutex ? sal_mutex_destroy(p_drv_master[lchip]->p_entry_mutex):0;
    p_drv_master[lchip]->p_pci_mutex ? sal_mutex_destroy(p_drv_master[lchip]->p_pci_mutex):0;
    p_drv_master[lchip]->p_i2c_mutex ? sal_mutex_destroy(p_drv_master[lchip]->p_i2c_mutex):0;
    p_drv_master[lchip]->p_sup1_entry_mutex ? sal_mutex_destroy(p_drv_master[lchip]->p_sup1_entry_mutex):0;
    p_drv_master[lchip]->p_mmap_mutex ? sal_mutex_destroy(p_drv_master[lchip]->p_mmap_mutex):0;
#else
    p_drv_master[lchip]->p_entry_mutex ? sal_spinlock_destroy((sal_spinlock_t*)p_drv_master[lchip]->p_entry_mutex):0;
    p_drv_master[lchip]->p_pci_mutex ? sal_spinlock_destroy((sal_spinlock_t*)p_drv_master[lchip]->p_pci_mutex):0;
    p_drv_master[lchip]->p_i2c_mutex ? sal_spinlock_destroy((sal_spinlock_t*)p_drv_master[lchip]->p_i2c_mutex):0;
    p_drv_master[lchip]->p_sup1_entry_mutex ? sal_spinlock_destroy((sal_spinlock_t*)p_drv_master[lchip]->p_sup1_entry_mutex):0;
    p_drv_master[lchip]->p_mmap_mutex ? sal_spinlock_destroy((sal_spinlock_t*)p_drv_master[lchip]->p_mmap_mutex):0;
#endif
    p_drv_master[lchip]->p_hss_mutex ? sal_mutex_destroy(p_drv_master[lchip]->p_hss_mutex):0;
    p_drv_master[lchip]->mpls_acc_mutex ? sal_mutex_destroy(p_drv_master[lchip]->mpls_acc_mutex):0;
    p_drv_master[lchip]->gemport_acc_mutex ? sal_mutex_destroy(p_drv_master[lchip]->gemport_acc_mutex):0;
    p_drv_master[lchip]->p_mep_mutex ? sal_mutex_destroy(p_drv_master[lchip]->p_mep_mutex):0;
    p_drv_master[lchip]->p_tcam_write_mutex ? sal_mutex_destroy(p_drv_master[lchip]->p_tcam_write_mutex):0;

    if(DRV_IS_TSINGMA(lchip))
    {
        uint8 mem_id;
        for(mem_id=DRV_FTM_TCAM_KEY0; mem_id<=DRV_FTM_LPM_TCAM_KEY11; mem_id++)
        {
            if(p_drv_master[lchip]->p_mem_info[mem_id].index_map)
            {
                mem_free(p_drv_master[lchip]->p_mem_info[mem_id].index_map);
            }
        }
        mem_free(p_drv_master[lchip]->p_mem_info);

        for(mem_id=0; mem_id < 3; mem_id++)
        {
            if(p_drv_master[lchip]->lpm_index_map[mem_id])
            {
                mem_free(p_drv_master[lchip]->lpm_index_map[mem_id]);
            }
        }
    }
    sal_memset(&(g_drv_master[pp_base]), 0, sizeof(drv_master_t));

    return 0;
}
uint32
drv_usw_get_flow_tcam_entry_num(uint8 lchip, uint16 mem_id)
{
    return p_drv_master[lchip] ? p_drv_master[lchip]->p_mem_info[mem_id+DRV_FTM_TCAM_KEY0].entry_num : 0;
}
int32
drv_mem_map(uint8 lchip, uint16 mem_id, uint32 invalid_bmp[])
{
    uint16 loop=0;
    uint16 logic_idx = 0;
    uint16 invalid_cnt = 0;
    drv_mem_t* p_mem = &p_drv_master[lchip]->p_mem_info[mem_id];
    if(NULL == p_mem->index_map)
    {
        p_mem->index_map = (uint16*)mem_malloc(MEM_SYSTEM_MODULE, sizeof(uint16)*p_mem->entry_num);
        if(NULL == p_mem->index_map)
        {
            return DRV_E_NO_MEMORY;
        }
    }
    for(loop=0; loop < p_mem->entry_num; loop++ )
    {
        if(DRV_BMP_ISSET(invalid_bmp, loop))
        {
            invalid_cnt++;
        }
        else
        {
            p_mem->index_map[logic_idx++] = loop;
        }
    }
    p_mem->entry_num -= invalid_cnt;
    if(DRV_FTM_TCAM_KEY0 <=mem_id && mem_id <= DRV_FTM_TCAM_KEY18)
    {
        p_drv_master[lchip]->p_mem_info[mem_id-DRV_FTM_TCAM_KEY0+DRV_FTM_TCAM_AD0].entry_num -= invalid_cnt;
    }
    else
    {
        p_drv_master[lchip]->p_mem_info[mem_id-DRV_FTM_LPM_TCAM_KEY0+DRV_FTM_LPM_TCAM_AD0].entry_num -= invalid_cnt;
    }
    return DRV_E_NONE;
}
int32
drv_lpm_tcam_map(uint8 lchip, uint16 mem_id, uint32 invalid_bmp[])
{
    uint8  lpm_mem_id;
    uint16 loop;
    uint16 logic_idx;
    uint16 mapped_idx_base;
    uint16  phy_number_per_mem = 0;

    if(mem_id < DRV_FTM_LPM_TCAM_KEY0 || mem_id > DRV_FTM_LPM_TCAM_KEY11)
    {
        return DRV_E_NONE;
    }
    phy_number_per_mem = (mem_id < DRV_FTM_LPM_TCAM_KEY8) ? 1024 : 2048;
    lpm_mem_id = (mem_id-DRV_FTM_LPM_TCAM_KEY0);
    if((lpm_mem_id % 4) == 0)
    {
        logic_idx = 0;
        mapped_idx_base = 0;
    }
    else if((lpm_mem_id % 4) == 1)
    {
        logic_idx = p_drv_master[lchip]->p_mem_info[mem_id-1].entry_num;
        mapped_idx_base = phy_number_per_mem;
    }
    else if((lpm_mem_id % 4) == 2)
    {
        logic_idx = p_drv_master[lchip]->p_mem_info[mem_id-1].entry_num + \
            p_drv_master[lchip]->p_mem_info[mem_id-2].entry_num;
        mapped_idx_base = phy_number_per_mem*2;
    }
    else
    {
        logic_idx = p_drv_master[lchip]->p_mem_info[mem_id-1].entry_num + \
            p_drv_master[lchip]->p_mem_info[mem_id-2].entry_num + \
            p_drv_master[lchip]->p_mem_info[mem_id-3].entry_num;
        mapped_idx_base = phy_number_per_mem*3;
    }
    if(NULL == p_drv_master[lchip]->lpm_index_map[lpm_mem_id>>2])
    {
        uint16 entries = (lpm_mem_id < 8) ? 4096:8192;
        p_drv_master[lchip]->lpm_index_map[lpm_mem_id>>2] = (uint16*)mem_malloc(MEM_SYSTEM_MODULE, sizeof(uint16)*entries);
        if(NULL == p_drv_master[lchip]->lpm_index_map[lpm_mem_id>>2])
        {
            return DRV_E_NO_MEMORY;
        }
    }
    for(loop=0; loop < phy_number_per_mem; loop++ )
    {
        if(!DRV_BMP_ISSET(invalid_bmp, loop))
        {
            p_drv_master[lchip]->lpm_index_map[lpm_mem_id>>2][logic_idx++] = loop+mapped_idx_base;
        }
    }

    return DRV_E_NONE;
}

int32 drv_lpm_nat_tcam_map_index(uint8 lchip, uint32 key_index)
{
    DRV_INIT_CHECK(lchip);
    return (p_drv_master[lchip]->lpm_index_map[2])?p_drv_master[lchip]->lpm_index_map[2][key_index] : key_index;
}
int32 drv_usw_show_tcam_error_count(uint8 lchip)
{
    uint16 mem_id;
    uint32 hw_entry_num;
    DRV_INIT_CHECK(lchip);

    for(mem_id = DRV_FTM_TCAM_KEY0; mem_id <= DRV_FTM_TCAM_KEY18; mem_id++)
    {
        if(NULL == p_drv_master[lchip]->p_mem_info[mem_id].index_map)
        {
            continue;
        }
        hw_entry_num = (mem_id < DRV_FTM_TCAM_KEY15) ? 1024 : 2048;
        DRV_DUMP_INFO("FLOW TCAM(%u) BIST Error Count(640bits): %u\n", (mem_id-DRV_FTM_TCAM_KEY0), (hw_entry_num-p_drv_master[lchip]->p_mem_info[mem_id].entry_num)/8);

    }
    for(mem_id = DRV_FTM_LPM_TCAM_KEY0; mem_id <= DRV_FTM_LPM_TCAM_KEY11; mem_id++)
    {
        if(NULL == p_drv_master[lchip]->p_mem_info[mem_id].index_map)
        {
            continue;
        }
        hw_entry_num = (mem_id < DRV_FTM_LPM_TCAM_KEY8) ? 1024 : 2048;
        DRV_DUMP_INFO("LPM TCAM(%u) BIST Error Count(184bits): %u\n", (mem_id-DRV_FTM_LPM_TCAM_KEY0), (hw_entry_num-p_drv_master[lchip]->p_mem_info[mem_id].entry_num)/4);

    }
    return 0;
}
